home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / AMScen_0_9.lha / AMScen / util.m < prev    next >
Text File  |  1995-01-21  |  70KB  |  2,819 lines

  1. /*
  2.  * Amiga MUD
  3.  *
  4.  * Copyright (c) 1995 by Chris Gray
  5.  */
  6.  
  7. /*
  8.  * util.m - a bunch of handy utility routines. Also some core routines for
  9.  *    some standard things used in most dungeons.
  10.  */
  11.  
  12. private tp_util CreateTable().
  13. use tp_util
  14.  
  15. define tp_util ForwardReference CreateThing(nil).
  16. define tp_util pDoMove CreateActionProp().
  17.  
  18. /* codes for use with LeaveRoomStuff and EnterRoomStuff */
  19.  
  20. define t_util MOVE_NORMAL    0.
  21. define t_util MOVE_POOF     1.
  22. define t_util MOVE_SPECIAL    2.
  23.  
  24. /* some standard types of rooms */
  25.  
  26. define t_roomTypes r_indoors CreateThing(nil).
  27. r_indoors@p_rScenery := "floor,wall,ceiling".
  28. AutoGraphics(r_indoors, AutoClosedRoom);
  29. SetThingStatus(r_indoors, ts_readonly).
  30.  
  31. define t_roomTypes r_outdoors CreateThing(nil).
  32. r_outdoors@p_rScenery := "ground,sky".
  33. AutoGraphics(r_outdoors, AutoPaths);
  34. SetThingStatus(r_outdoors, ts_readonly).
  35.  
  36. define t_roomTypes r_path CreateThing(r_outdoors).
  37. r_path@p_rScenery := "ground,sky,path,trail,bush,bushes,grass".
  38. AutoGraphics(r_path, AutoPaths);
  39. SetThingStatus(r_path, ts_readonly).
  40.  
  41. define t_roomTypes r_road CreateThing(r_outdoors).
  42. r_road@p_rScenery := "ground,sky,road,dirt,alley".
  43. AutoGraphics(r_road, AutoRoads);
  44. SetThingStatus(r_road, ts_readonly).
  45.  
  46. define t_roomTypes r_forest CreateThing(r_outdoors).
  47. r_forest@p_rScenery :=
  48.     "ground,sky,path,trail,grass,bush,bushes,tree,leaf,leaves,foliage".
  49. AutoGraphics(r_forest, AutoPaths);
  50. AutoPens(r_forest, C_FOREST_GREEN, C_DARK_GREEN, 0, 0).
  51. SetThingStatus(r_forest, ts_readonly).
  52.  
  53. define t_roomTypes r_field CreateThing(r_outdoors).
  54. r_field@p_rScenery := "ground,sky,path,trail,grass,field,pasture.".
  55. AutoGraphics(r_field, AutoOpenSpace);
  56. SetThingStatus(r_field, ts_readonly).
  57.  
  58. define t_roomTypes r_sidewalk CreateThing(r_outdoors).
  59. r_sidewalk@p_rScenery := "ground,sky,sidewalk,pavement,road".
  60. AutoGraphics(r_sidewalk, AutoPaths);
  61. SetThingStatus(r_sidewalk, ts_readonly).
  62.  
  63. define t_roomTypes r_park CreateThing(r_outdoors).
  64. r_park@p_rScenery :=
  65.     "ground,sky,sidewalk,fountain,tree,bush,bushes,grass.park".
  66. AutoGraphics(r_park, AutoOpenSpace);
  67. SetThingStatus(r_park, ts_readonly).
  68.  
  69. define t_roomTypes r_tunnel CreateThing(r_indoors).
  70. r_tunnel@p_rScenery := "floor,ground,wall,side,roof,ceiling,rock,stone".
  71. AutoGraphics(r_tunnel, AutoTunnels);
  72. SetThingStatus(r_tunnel, ts_readonly).
  73.  
  74. /* some routines to help us build a world */
  75.  
  76. /*
  77.  * ExtendDesc - add some stuff to a room description - this is used when
  78.  *    adding a room to an already existing setup.
  79.  */
  80.  
  81. define t_util proc utility public ExtendDesc(thing room; string desc)void:
  82.     string s;
  83.  
  84.     s := room@p_rDesc;
  85.     if s = "" then
  86.     s := desc;
  87.     else
  88.     s := s + " " + desc;
  89.     fi;
  90.     room@p_rDesc := s;
  91. corp;
  92.  
  93. /*
  94.  * Scenery - add some names that will be found by 'look', etc., but that
  95.  *    have nothing special about them. Doing it this way saves creating
  96.  *    a lot of extra things.
  97.  */
  98.  
  99. define t_util proc utility public Scenery(thing room; string newScenery)void:
  100.     string oldScenery;
  101.  
  102.     oldScenery := room@p_rScenery;
  103.     if oldScenery ~= "" then
  104.     newScenery := oldScenery + "." + newScenery;
  105.     fi;
  106.     room@p_rScenery := newScenery;
  107. corp;
  108.  
  109. /*
  110.  * Sign - create a dummy sign.
  111.  */
  112.  
  113. define t_util proc utility public Sign(thing room; string name, desc,text)void:
  114.     thing sign;
  115.  
  116.     sign := CreateThing(nil);
  117.     sign@p_oName := name;
  118.     if desc ~= "" then
  119.     sign@p_oDesc := desc;
  120.     fi;
  121.     sign@p_oReadString := text;
  122.     sign@p_oNotGettable := true;
  123.     sign@p_oInvisible := true;
  124.     SetThingStatus(sign, ts_readonly);
  125.     AddTail(room@p_rContents, sign);
  126. corp;
  127.  
  128. /*
  129.  * Several variants for setting up rooms. Note: the 'P' variants are the
  130.  *    same as the non-P forms, except that they make the room public,
  131.  *    i.e. add-to-able by others.
  132.  *    The base variant takes the room, the name string, and an optional
  133.  *    description string.
  134.  */
  135.  
  136. define t_util proc utility public SetupRoom(thing room; string name, desc)void:
  137.  
  138.     room@p_rName := name;
  139.     if desc ~= "" then
  140.     room@p_rDesc := desc;
  141.     fi;
  142.     room@p_rContents := CreateThingList();
  143.     room@p_rExits := CreateIntList();
  144.     SetThingStatus(room, ts_readonly);
  145. corp;
  146.  
  147. define t_util proc utility public SetupRoomP(thing room;
  148.     string name, desc)void:
  149.  
  150.     room@p_rName := name;
  151.     if desc ~= "" then
  152.     room@p_rDesc := desc;
  153.     fi;
  154.     room@p_rContents := CreateThingList();
  155.     room@p_rExits := CreateIntList();
  156.     SetThingStatus(room, ts_wizard);
  157. corp;
  158.  
  159. define t_util proc utility public SetupRoomD(thing room;
  160.     string name, desc)void:
  161.  
  162.     room@p_rName := name;
  163.     if desc ~= "" then
  164.     room@p_rDesc := desc;
  165.     fi;
  166.     room@p_rContents := CreateThingList();
  167.     room@p_rExits := CreateIntList();
  168.     SetThingStatus(room, ts_readonly);
  169.     room@p_rDark := true;
  170. corp;
  171.  
  172. define t_util proc utility public SetupRoomDP(thing room;
  173.     string name, desc)void:
  174.  
  175.     room@p_rName := name;
  176.     if desc ~= "" then
  177.     room@p_rDesc := desc;
  178.     fi;
  179.     room@p_rContents := CreateThingList();
  180.     room@p_rExits := CreateIntList();
  181.     SetThingStatus(room, ts_wizard);
  182.     room@p_rDark := true;
  183. corp;
  184.  
  185. /* This variant has no description, and a proc to provide the name.
  186.    This is useful with many similar rooms, to avoid duplicating the
  187.    name string. */
  188.  
  189. define t_util proc utility public SetupRoom2(thing room;
  190.     action nameAction)void:
  191.  
  192.     room@p_rNameAction := nameAction;
  193.     room@p_rContents := CreateThingList();
  194.     room@p_rExits := CreateIntList();
  195.     SetThingStatus(room, ts_readonly);
  196. corp;
  197.  
  198. define t_util proc utility public SetupRoom2P(thing room;
  199.     action nameAction)void:
  200.  
  201.     room@p_rNameAction := nameAction;
  202.     room@p_rContents := CreateThingList();
  203.     room@p_rExits := CreateIntList();
  204.     SetThingStatus(room, ts_wizard);
  205. corp;
  206.  
  207. /* Variant with name action, but a required description string */
  208.  
  209. define t_util proc utility public SetupRoom3(thing room; action nameAction;
  210.     string desc)void:
  211.  
  212.     room@p_rNameAction := nameAction;
  213.     room@p_rDesc := desc;
  214.     room@p_rContents := CreateThingList();
  215.     room@p_rExits := CreateIntList();
  216.     SetThingStatus(room, ts_readonly);
  217. corp;
  218.  
  219. define t_util proc utility public SetupRoom3P(thing room; action nameAction;
  220.     string desc)void:
  221.  
  222.     room@p_rNameAction := nameAction;
  223.     room@p_rDesc := desc;
  224.     room@p_rContents := CreateThingList();
  225.     room@p_rExits := CreateIntList();
  226.     SetThingStatus(room, ts_wizard);
  227. corp;
  228.  
  229. /* Similar utility to set up an object. Takes the object, an optional room
  230.    to put it in and to make its home, the name string, and an optional
  231.    description string. */
  232.  
  233. define t_util proc utility public SetupObject(thing object, where;
  234.     string name, desc)void:
  235.  
  236.     object@p_oName := name;
  237.     if desc ~= "" then
  238.     object@p_oDesc := desc;
  239.     fi;
  240.     if where ~= nil then
  241.     AddTail(where@p_rContents, object);
  242.     object@p_oHome := where;
  243.     object@p_oWhere := where;
  244.     fi;
  245.     SetThingStatus(object, ts_wizard);
  246. corp;
  247.  
  248. /* this one makes a fake, non-gettable object */
  249.  
  250. define t_util proc utility public FakeObject(thing object, where;
  251.     string name, desc)void:
  252.  
  253.     object@p_oName := name;
  254.     if desc ~= "" then
  255.     object@p_oDesc := desc;
  256.     fi;
  257.     object@p_oNotGettable := true;
  258.     object@p_oInvisible := true;
  259.     if where ~= nil then
  260.     AddTail(where@p_rContents, object);
  261.     fi;
  262.     SetThingStatus(object, ts_wizard);
  263. corp;
  264.  
  265. /* this one makes just a model for a fake, non-gettable object */
  266.  
  267. define t_util proc utility public FakeModel(thing object;
  268.     string name, desc)void:
  269.  
  270.     object@p_oName := name;
  271.     if desc ~= "" then
  272.     object@p_oDesc := desc;
  273.     fi;
  274.     object@p_oNotGettable := true;
  275.     object@p_oInvisible := true;
  276.     SetThingStatus(object, ts_wizard);
  277. corp;
  278.  
  279. /*
  280.  * DepositObject - add a clone of an object to the indicated room.
  281.  */
  282.  
  283. define t_util proc utility public DepositClone(thing room, model)void:
  284.     thing new;
  285.  
  286.     new := CreateThing(model);
  287.     AddTail(room@p_rContents, new);
  288.     new@p_oCreator := Me();
  289.     new@p_oWhere := room;
  290.     GiveThing(new, SysAdmin);
  291.     SetThingStatus(new, ts_public);
  292. corp;
  293.  
  294. /* Some utilities for making connections between rooms. 'Connect' is the
  295.    most useful one. */
  296.  
  297. define t_util proc utility public UniConnect(thing r1, r2; int dir)void:
  298.     list int exits;
  299.  
  300.     r1@DirProp(dir) := r2;
  301.     exits := r1@p_rExits;
  302.     if exits = nil then
  303.     exits := CreateIntList();
  304.     r1@p_rExits := exits;
  305.     fi;
  306.     AddTail(exits, dir);
  307. corp;
  308.  
  309. define t_util proc utility public BiConnect(thing r1, r2; int dir1, dir2)void:
  310.     list int exits;
  311.  
  312.     r1@DirProp(dir1) := r2;
  313.     exits := r1@p_rExits;
  314.     if exits = nil then
  315.     exits := CreateIntList();
  316.     r1@p_rExits := exits;
  317.     fi;
  318.     AddTail(exits, dir1);
  319.     r2@DirProp(dir2) := r1;
  320.     exits := r2@p_rExits;
  321.     if exits = nil then
  322.     exits := CreateIntList();
  323.     r2@p_rExits := exits;
  324.     fi;
  325.     AddTail(exits, dir2);
  326. corp;
  327.  
  328. define t_util proc utility public Connect(thing r1, r2; int dir)void:
  329.     list int exits;
  330.  
  331.     r1@DirProp(dir) := r2;
  332.     exits := r1@p_rExits;
  333.     if exits = nil then
  334.     exits := CreateIntList();
  335.     r1@p_rExits := exits;
  336.     fi;
  337.     AddTail(exits, dir);
  338.     dir := DirBack(dir);
  339.     r2@DirProp(dir) := r1;
  340.     exits := r2@p_rExits;
  341.     if exits = nil then
  342.     exits := CreateIntList();
  343.     r2@p_rExits := exits;
  344.     fi;
  345.     AddTail(exits, dir);
  346. corp;
  347.  
  348. /*
  349.  * HConnect is the same as UniConnect, except that the connection is not
  350.  *    added to the list of obvious exits.
  351.  */
  352.  
  353. define t_util proc utility public HConnect(thing r1, r2; int dir)void:
  354.  
  355.     r1@DirProp(dir) := r2;
  356.     r2@DirProp(DirBack(dir)) := r1;
  357. corp;
  358.  
  359. /*
  360.  * HUniConnect - a hidden one-way connection.
  361.  */
  362.  
  363. define t_util proc utility public HUniConnect(thing r1, r2; int dir)void:
  364.  
  365.     r1@DirProp(dir) := r2;
  366. corp;
  367.  
  368. /* some routines useful for verbs */
  369.  
  370. /*
  371.  * ShowExits - show the obvious exits from the current room.
  372.  */
  373.  
  374. define t_util proc public ShowExits(thing room)void:
  375.     list int li;
  376.     int count, i, oldIndent;
  377.  
  378.     li := room@p_rExits;
  379.     if li ~= nil then
  380.     count := Count(li);
  381.     if count = 0 then
  382.         Print("There are no obvious exits.\n");
  383.     else
  384.         Print("Obvious exits: ");
  385.         oldIndent := GetIndent();
  386.         SetIndent(oldIndent + 2);
  387.         for i from 0 upto count - 1 do
  388.         Print(ExitName(li[i]));
  389.         if i ~= count then
  390.             Print(" ");
  391.         fi;
  392.         od;
  393.         SetIndent(oldIndent);
  394.         Print("\n");
  395.     fi;
  396.     else
  397.     Print("There are no obvious exits.\n");
  398.     fi;
  399. corp;
  400.  
  401. /*
  402.  * ShowList - print out a contents/carrying list. Return 'true' if nothing
  403.  *    was printed.
  404.  */
  405.  
  406. define t_util proc utility public ShowList(list thing lt; string starter)bool:
  407.     int i;
  408.     thing object;
  409.     string s;
  410.     bool first;
  411.  
  412.     first := true;
  413.     for i from 0 upto Count(lt) - 1 do
  414.     object := lt[i];
  415.     if not object@p_oInvisible then
  416.         if first then
  417.         first := false;
  418.         Print(starter);
  419.         fi;
  420.         Print("  " + FormatName(object@p_oName) + "\n");
  421.     fi;
  422.     od;
  423.     first
  424. corp;
  425.  
  426. /*
  427.  * DoAll - do the given proc for each visible thing in the given list. Return
  428.  *    'continue' if at least one is done and all done yield 'true';
  429.  *    return 'succeed' if one does not return 'true', and return 'fail'
  430.  *    if there are none to do.
  431.  */
  432.  
  433. define t_util proc public DoAll(list thing lt; action a)status:
  434.     int count, i, oldCount;
  435.     thing th;
  436.     bool ok, doneOne;
  437.  
  438.     count := Count(lt);
  439.     doneOne := false;
  440.     i := 0;
  441.     ok := true;
  442.     while ok and i ~= count do
  443.     th := lt[i];
  444.     if not th@p_oInvisible then
  445.         doneOne := true;
  446.         if call(a, bool)(th) then
  447.         oldCount := count;
  448.         count := Count(lt);
  449.         i := i - (oldCount - count) + 1;
  450.         else
  451.         ok := false;
  452.         fi;
  453.     else
  454.         i := i + 1;
  455.     fi;
  456.     od;
  457.     if doneOne then
  458.     if ok then continue else succeed fi
  459.     else
  460.     fail
  461.     fi
  462. corp;
  463.  
  464. /* NOTE: When a monster is killed, DoDrop is called to drop whatever it is
  465.    carrying. That in turn calls CanSee, with 'thePlayer' set to the monster. */
  466.  
  467. define t_util proc public CanSee(thing theRoom, thePlayer)bool:
  468.  
  469.     if not theRoom@p_rDark then
  470.     true
  471.     else
  472.     if thePlayer ~= nil and not thePlayer@p_pStandard then
  473.         thePlayer := Me();
  474.     fi;
  475.     if thePlayer = nil then
  476.         FindFlagOnList(theRoom@p_rContents, p_oLight) or
  477.         FindAgentWithFlag(theRoom, p_oLight) ~= nil or
  478.         FindAgentWithFlagOnList(theRoom, p_pCarrying, p_oLight) ~= nil
  479.     elif thePlayer@p_oLight then
  480.         true
  481.     else
  482.         FindFlagOnList(thePlayer@p_pCarrying, p_oLight) or
  483.         FindFlagOnList(theRoom@p_rContents, p_oLight) or
  484.         FindAgentWithFlag(theRoom, p_oLight) ~= nil or
  485.         FindAgentWithFlagOnList(theRoom, p_pCarrying, p_oLight) ~= nil
  486.     fi
  487.     fi
  488. corp;
  489.  
  490. /*
  491.  * LightAt - return 'true' if there is light in the given room, without
  492.  *    the current player being considered to be there.
  493.  */
  494.  
  495. define t_util proc public LightAt(thing theRoom)bool:
  496.  
  497.     not theRoom@p_rDark or
  498.     FindFlagOnList(theRoom@p_rContents, p_oLight) or
  499.     FindAgentWithFlag(theRoom, p_oLight) ~= nil or
  500.     FindAgentWithFlagOnList(theRoom, p_pCarrying, p_oLight) ~= nil
  501. corp;
  502.  
  503. /*
  504.  * HasLight - return 'true' if the given thing (character) supplies light.
  505.  */
  506.  
  507. define t_util proc public HasLight(thing who)bool:
  508.  
  509.     who@p_oLight or FindFlagOnList(who@p_pCarrying, p_oLight)
  510. corp;
  511.  
  512. /*
  513.  * CarryingChild - return any child of the given thing that the given
  514.  *    player is carrying, either directly or indirectly.
  515.  */
  516.  
  517. define tp_util proc containsChild(list thing lt; thing what)thing:
  518.     int count, i;
  519.     thing th;
  520.  
  521.     count := Count(lt);
  522.     i := 0;
  523.     while i < count do
  524.     th := lt[i];
  525.     if Parent(th) = what then
  526.         i := count + 1;
  527.     elif th@p_oContents ~= nil then
  528.         th := containsChild(th@p_oContents, what);
  529.         if th ~= nil then
  530.         i := count + 1;
  531.         else
  532.         i := i + 1;
  533.         fi;
  534.     else
  535.         i := i + 1;
  536.     fi;
  537.     od;
  538.     if i > count then th else nil fi
  539. corp;
  540.  
  541. define t_util proc CarryingChild(thing who, what)thing:
  542.     containsChild(who@p_pCarrying, what)
  543. corp;
  544.  
  545. /*
  546.  * ChildHere - return any child of the given thing that the given room
  547.  *    contains, either directly or indirectly.
  548.  */
  549.  
  550. define t_util proc ChildHere(thing room, what)thing:
  551.     containsChild(room@p_rContents, what)
  552. corp;
  553.  
  554. /*
  555.  * ShowPosition - show the position of the given player/character.
  556.  */
  557.  
  558. define t_util proc public ShowPosition(thing th)void:
  559.     int pos;
  560.  
  561.     pos := th@p_pPosition;
  562.     if pos ~= POS_NONE then
  563.     case pos
  564.     incase POS_SIT_IN:
  565.         Print("sitting in");
  566.     incase POS_SIT_ON:
  567.         Print("sitting on");
  568.     incase POS_LIE_IN:
  569.         Print("lying in");
  570.     incase POS_LIE_ON:
  571.         Print("lying on");
  572.     incase POS_STAND_IN:
  573.         Print("standing in");
  574.     incase POS_STAND_ON:
  575.         Print("standing on");
  576.     esac;
  577.     Print(" the " + FormatName(th@p_pWhere@p_oName) + ".\n");
  578.     else
  579.     Print("here.\n");
  580.     fi;
  581. corp;
  582.  
  583. /*
  584.  * ZapObject - destroy an object, and anything it contains.
  585.  */
  586.  
  587. define t_util proc public ZapObject(thing object)void:
  588.     list thing lt;
  589.     int count;
  590.     thing th;
  591.  
  592.     lt := object@p_oContents;
  593.     if lt ~= nil then
  594.     count := Count(lt);
  595.     while count ~= 0 do
  596.         count := count - 1;
  597.         th := lt[count];
  598.         ZapObject(th);
  599.         DelElement(lt, th);
  600.     od;
  601.     fi;
  602.     ClearThing(object);
  603. corp;
  604.  
  605. /*
  606.  * SayToList - output a given message to each location on a list.
  607.  */
  608.  
  609. define t_util proc SayToList(list thing lt; string message)void:
  610.     int i;
  611.  
  612.     for i from 0 upto Count(lt) - 1 do
  613.     ABPrint(lt[i], nil, nil, message);
  614.     od;
  615. corp;
  616.  
  617. /*
  618.  * CharacterDescription - return the normal description of the passed character
  619.  */
  620.  
  621. define t_util proc CharacterDescription(thing who)string:
  622.     string s;
  623.     action a;
  624.  
  625.     SetIt(who);
  626.     a := who@p_pDescAction;
  627.     if a = nil then
  628.     s := who@p_pDesc;
  629.     else
  630.     s := call(a, string)();
  631.     fi;
  632.     s + DoActionsString(who@p_pDescMore)
  633. corp;
  634.  
  635. /*
  636.  * LookAtCharacter - take a detailed look at the given player/monster.
  637.  */
  638.  
  639. define t_util proc LookAtCharacter(thing who)bool:
  640.     action a;
  641.     status st;
  642.     string name, s;
  643.  
  644.     st := continue;
  645.     a := who@p_pDescCheck;
  646.     if a ~= nil then
  647.     /* if p_pDescCheck returns 'continue', all is well and we
  648.        will continue looking at the player, and around. If it
  649.        returns 'succeed', then we are done looking at the
  650.        player, but can look around. If it returns 'fail', then
  651.        we cannot look anymore (or some such). */
  652.     SetIt(who);
  653.     st := call(a, status)();
  654.     fi;
  655.     if st = continue then
  656.     s := CharacterDescription(who);
  657.     name := FormatName(who@p_pName);
  658.     if s = "" then
  659.         s := name + " has no description - bug him/her about it."
  660.     fi;
  661.     Print(s + "\n");
  662.     if who = Me() then
  663.         s := "You are carrying:\n";
  664.     else
  665.         s := name + " is carrying:\n";
  666.     fi;
  667.     ignore ShowList(who@p_pCarrying, s);
  668.     true
  669.     else
  670.     st = succeed
  671.     fi
  672. corp;
  673.  
  674. /* NOTE: for the following sets of routines, the code usually just calls the
  675.    the inner (one/once) routine directly via ForEachAgent, just to save one
  676.    interpreted subroutine call. */
  677.  
  678. /*
  679.  * ShowAgents - show who/what is in the current room.
  680.  */
  681.  
  682. define t_util proc public ShowOneAgent(thing th)void:
  683.  
  684.     if th@p_pName ~= "" and not th@p_pHidden then
  685.     Print(FormatName(th@p_pName) + " is ");
  686.     ShowPosition(th);
  687.     GShowIcon(nil, th, not th@p_pStandard, Parent(th) ~= nil);
  688.     fi;
  689. corp;
  690.  
  691. define t_util proc public ShowAgents()void:
  692.  
  693.     ForEachAgent(Here(), ShowOneAgent);
  694. corp;
  695.  
  696. /*
  697.  * ShowRoomTo - show the room to someone who is in it.
  698.  */
  699.  
  700. define t_util proc ShowRoomToMe(bool full)bool:
  701.     thing me, room;
  702.     action a;
  703.     string s;
  704.     status st;
  705.  
  706.     me := Me();
  707.     room := Here();
  708.     a := room@p_rNameAction;
  709.     if a = nil then
  710.     s := room@p_rName;
  711.     else
  712.     s := call(a, string)();
  713.     fi;
  714.     if s ~= "" then
  715.     Print("You are " + s + ".\n");
  716.     fi;
  717.     /* looking around the room can "fail" or "succeed" */
  718.     st := DoRoomLookChecks(room);
  719.     if st ~= fail then
  720.     if st = continue then
  721.         if full or me@p_pVerbose then
  722.         /* it may seem redundant to allow for both 'rLookChecks'
  723.            and 'rDescAction', but what the heck! */
  724.         a := room@p_rDescAction;
  725.         if a = nil then
  726.             s := room@p_rDesc;
  727.             if s = "" then
  728.             Print("You see nothing special here.\n");
  729.             else
  730.             Print(s + "\n");
  731.             fi;
  732.             ShowExits(room);
  733.         else
  734.             Print(call(a, string)() + "\n");
  735.         fi;
  736.         elif not me@p_pSuperBrief then
  737.         ShowExits(room);
  738.         fi;
  739.     fi;
  740.     ignore ShowList(room@p_rContents, "Nearby:\n");
  741.     if GOn(nil) then
  742.         GUndrawIcons(nil);
  743.         GResetIcons(nil);
  744.         a := room@p_rEnterRoomDraw;
  745.         if a ~= nil then
  746.         RemoveCursor();
  747.         call(a, void)();
  748.         fi;
  749.     fi;
  750.     ForEachAgent(room, ShowOneAgent);
  751.     a := room@p_rFurtherDesc;
  752.     if a ~= nil then
  753.         call(a, void)();
  754.     fi;
  755.     true
  756.     else
  757.     false
  758.     fi
  759. corp;
  760.  
  761. define tp_util proc doShowRoom()status:
  762.  
  763.     ignore ShowRoomToMe(false);
  764.     continue
  765. corp;
  766.  
  767. define t_util proc ShowRoomToAgent(thing who)void:
  768.  
  769.     /* no need to do anything for machines */
  770.     if who ~= Me() and ThingCharacter(who) ~= nil then
  771.     ignore ForceAction(who, doShowRoom);
  772.     fi;
  773. corp;
  774.  
  775. define t_util proc UnShowRoomFromMe()void:
  776.     action a;
  777.  
  778.     if GOn(nil) then
  779.     GUndrawIcons(nil);
  780.     GResetIcons(nil);
  781.     a := Here()@p_rLeaveRoomDraw;
  782.     if a ~= nil then
  783.         call(a, void)(nil);
  784.     fi;
  785.     fi;
  786. corp;
  787.  
  788. define tp_util proc doUnShowRoom()status:
  789.  
  790.     UnShowRoomFromMe();
  791.     continue
  792. corp;
  793.  
  794. define t_util proc UnShowRoomFromAgent(thing who)void:
  795.  
  796.     if who ~= Me() and ThingCharacter(who) ~= nil then
  797.     /* only do it for players */
  798.     ignore ForceAction(who, doUnShowRoom);
  799.     fi;
  800. corp;
  801.  
  802. /* some code to aid the 'follow' verb. */
  803.  
  804. define tp_util p_pOldHere CreateThingProp().
  805. define tp_util p_pMeFollowDir CreateIntProp().
  806. define tp_util p_pFollowMeDir CreateIntProp().
  807.  
  808. define t_util proc Follow(thing leader)void:
  809.     list thing followers;
  810.  
  811.     followers := leader@p_pFollowers;
  812.     if followers = nil then
  813.     followers := CreateThingList();
  814.     leader@p_pFollowers := followers;
  815.     leader@p_pFollowMeDir := -1;
  816.     fi;
  817.     AddTail(followers, Me());
  818.     Me()@p_pFollowing := leader;
  819.     Me()@p_pMeFollowDir := -1;
  820. corp;
  821.  
  822. define tp_util proc doFollow()status:
  823.     thing me;
  824.     int dir;
  825.  
  826.     me := Me();
  827.     dir := me@p_pMeFollowDir;
  828.     Print("You follow " + FormatName(me@p_pFollowing@p_pName) + " to " +
  829.     DirName(dir) + ".\n");
  830.     if call(ForwardReference@pDoMove, bool)(dir) then
  831.     continue
  832.     else
  833.     fail
  834.     fi
  835. corp;
  836.  
  837. define tp_util proc doCheckFollowers()void:
  838.     list thing followers;
  839.     thing oldHere, leader, follower;
  840.     int dir, i;
  841.  
  842.     leader := Me();
  843.     followers := leader@p_pFollowers;
  844.     if followers ~= nil then
  845.     oldHere := leader@p_pOldHere;
  846.     dir := leader@p_pFollowMeDir;
  847.     i := Count(followers);
  848.     while i ~= 0 do
  849.         i := i - 1;
  850.         follower := followers[i];
  851.         if follower@p_pFollowing = leader and
  852.         AgentLocation(follower) = oldHere
  853.         then
  854.         follower@p_pMeFollowDir := dir;
  855.         if ForceAction(follower, doFollow) ~= continue
  856.         then
  857.             /* the follow failed - remove this follower */
  858.             /* note that we specifically do not inform the
  859.                follower! */
  860.             follower -- p_pFollowing;
  861.             follower -- p_pMeFollowDir;
  862.             DelElement(followers, follower);
  863.         fi;
  864.         else
  865.         /* Again, we do not inform the follower - that could tell
  866.            him that the one he was following has moved, when he
  867.            should not normally know that. */
  868.         follower -- p_pFollowing;
  869.         follower -- p_pMeFollowDir;
  870.         DelElement(followers, follower);
  871.         fi;
  872.     od;
  873.     if Count(followers) = 0 then
  874.         leader -- p_pFollowers;
  875.         leader -- p_pFollowMeDir;
  876.     fi;
  877.     fi;
  878. corp;
  879.  
  880. define t_util proc CheckFollowers(thing here; int dir)void:
  881.     thing me;
  882.  
  883.     me := Me();
  884.     if me@p_pFollowers ~= nil then
  885.     me@p_pOldHere := here;
  886.     me@p_pFollowMeDir := dir;
  887.     After(0, doCheckFollowers);
  888.     fi;
  889. corp;
  890.  
  891. define t_util proc ClearFollowers(thing leader)void:
  892.     list thing followers;
  893.     thing follower;
  894.     int i;
  895.     string name;
  896.  
  897.     followers := leader@p_pFollowers;
  898.     if followers ~= nil then
  899.     name := FormatName(leader@p_pName);
  900.     for i from 0 upto Count(followers) - 1 do
  901.         follower := followers[i];
  902.         if follower@p_pFollowing = leader then
  903.         follower -- p_pFollowing;
  904.         follower -- p_pMeFollowDir;
  905.         SPrint(follower,"You are no longer following " + name + ".\n");
  906.         fi;
  907.     od;
  908.     leader -- p_pFollowers;
  909.     leader -- p_pFollowMeDir;
  910.     fi;
  911. corp;
  912.  
  913. define t_util proc UnFollow()void:
  914.     list thing followers;
  915.     thing me, leader;
  916.  
  917.     me := Me();
  918.     leader := me@p_pFollowing;
  919.     if leader ~= nil then
  920.     me -- p_pFollowing;
  921.     me -- p_pMeFollowDir;
  922.     Print("You stop following " + FormatName(leader@p_pName) + ".\n");
  923.     followers := leader@p_pFollowers;
  924.     if followers ~= nil then
  925.         DelElement(followers, me);
  926.         if Count(followers) = 0 then
  927.         leader -- p_pFollowers;
  928.         leader -- p_pFollowMeDir;
  929.         fi;
  930.     fi;
  931.     fi;
  932. corp;
  933.  
  934. /* general code dealing with entering and exiting rooms, moving, etc. */
  935.  
  936. define t_util proc EnterRoomStuff(thing dest; int fromDir, moveKind)void:
  937.     thing me;
  938.     bool lightThere;
  939.     string name, s;
  940.  
  941.     DoRoomAnyEnterActions(dest);
  942.     me := Me();
  943.     lightThere := LightAt(dest);
  944.     SetLocation(dest);
  945.     if lightThere or me@p_oLight or FindFlagOnList(me@p_pCarrying, p_oLight)
  946.     then
  947.     ignore ShowRoomToMe(false);
  948.     /* if I can't see, neither can anyone else */
  949.     if not me@p_pHidden then
  950.         if lightThere then
  951.         ForEachAgent(dest, ShowIconOnce);
  952.         fi;
  953.         name := FormatName(me@p_pName);
  954.         case moveKind
  955.         incase MOVE_NORMAL:
  956.         if fromDir >= 0 then
  957.             s := dest@(DirEMessage(fromDir));
  958.             if s = "" then
  959.             OPrint(name + " has arrived from " +
  960.                 DirName(fromDir) + ".\n");
  961.             elif s ~= "." then
  962.             OPrint(name + " " + s + "\n");
  963.             fi;
  964.         fi;
  965.         incase MOVE_POOF:
  966.         OPrint(name + " *POOFS* in.\n");
  967.         esac;
  968.     else
  969.         if moveKind = MOVE_POOF then
  970.         OPrint("*POOF*\n");
  971.         fi;
  972.     fi;
  973.     if not lightThere then
  974.         ForEachAgent(dest, ShowRoomToAgent);
  975.     fi;
  976.     else
  977.     Print("It is dark here.\n");
  978.     if dest@p_rEnterRoomDraw ~= nil and GOn(nil) then
  979.         UnShowRoomFromMe();
  980.     fi;
  981.     fi;
  982. corp;
  983.  
  984. /*
  985.  * similar stuff for the going out of a room half.
  986.  */
  987.  
  988. define t_util proc LeaveRoomStuff(thing dest; int dir, moveKind)void:
  989.     thing me, here;
  990.     action a;
  991.     string name, s;
  992.     bool lightHere;
  993.  
  994.     me := Me();
  995.     here := Here();
  996.     SetLocation(nil);
  997.     lightHere := LightAt(here);
  998.     if lightHere or me@p_oLight or FindFlagOnList(me@p_pCarrying, p_oLight)
  999.     then
  1000.     name := FormatName(me@p_pName);
  1001.     /* have to use ABPrint, since we have done SetLocation(nil) */
  1002.     case moveKind
  1003.     incase MOVE_NORMAL:
  1004.         if not me@p_pHidden then
  1005.         s := here@(DirOMessage(dir));
  1006.         if s = "" then
  1007.             ABPrint(here, me, me,
  1008.             name + " has left to " + DirName(dir) + ".\n");
  1009.         elif s ~= "." then
  1010.             ABPrint(here, me, me, name + " " + s + "\n");
  1011.         fi;
  1012.         CheckFollowers(here, dir);
  1013.         fi;
  1014.         /* we keep the rest in case he/she went hidden while here */
  1015.         s := here@(DirMessage(dir));
  1016.         if s ~= "" then
  1017.         NPrint(s);
  1018.         fi;
  1019.     incase MOVE_POOF:
  1020.         if me@p_pHidden then
  1021.         ABPrint(here, me, me, "*POOF*\n");
  1022.         else
  1023.         ABPrint(here, me, me, name + " *POOFS* out.\n");
  1024.         fi;
  1025.         Print("*POOF*\n");
  1026.         ClearFollowers(me);
  1027.         UnFollow();
  1028.     esac;
  1029.     ForEachAgent(here, UnShowIconOnce);
  1030.     if GOn(nil) then
  1031.         GUndrawIcons(nil);
  1032.         GResetIcons(nil);
  1033.         a := here@p_rLeaveRoomDraw;
  1034.         if a ~= nil then
  1035.         call(a, void)(dest);
  1036.         fi;
  1037.     fi;
  1038.     if not lightHere then
  1039.         ForEachAgent(here, UnShowRoomFromAgent);
  1040.     fi;
  1041.     fi;
  1042.     /* put the location back to the old room for DoRoomAnyEnterActions */
  1043.     SetLocation(here);
  1044. corp;
  1045.  
  1046. /*
  1047.  * EnterRoom - called whenever the player finally enters a given room.
  1048.  *    Returns 'true' if all is well and we should continue with commands.
  1049.  */
  1050.  
  1051. define t_util proc public EnterRoom(thing dest; int dir, moveType)bool:
  1052.  
  1053.     LeaveRoomStuff(dest, dir, moveType);
  1054.     EnterRoomStuff(dest, DirBack(dir), moveType);
  1055.     ignore DoPlayerEnterChecks(Me());
  1056.     /* allow for funny things like instant teleports out, etc. */
  1057.     DoRoomAnyEnterChecks(dest) ~= fail
  1058. corp;
  1059.  
  1060. /*
  1061.  * DoMove - bottom level routine to attempt to move in the given direction.
  1062.  *    Note: not suitable for other than called by the player.
  1063.  *    Other Note: it should work indirectly for machines, e.g. when
  1064.  *        someone does 'say Packrat go north'.
  1065.  */
  1066.  
  1067. define t_util proc public DoMove(int dir)bool:
  1068.     thing me, here, dest;
  1069.     string s;
  1070.     action a;
  1071.  
  1072.     me := Me();
  1073.     if me@p_pPosition ~= POS_NONE then
  1074.     Print("You are still ");
  1075.     ShowPosition(me);
  1076.     false
  1077.     else
  1078.     here := Here();
  1079.     dest := here@(DirProp(dir));
  1080.     if dest = nil then
  1081.         a := here@p_rNoGoAction;
  1082.         if a ~= nil then
  1083.         call(a, void)(dir);
  1084.         else
  1085.         s := here@p_rNoGoString;
  1086.         if s ~= "" then
  1087.             NPrint(s);
  1088.         else
  1089.             Print("You can't go in that direction.\n");
  1090.         fi;
  1091.         fi;
  1092.         false
  1093.     elif dest@p_rLocked and CharacterThing(Owner(dest)) ~= me and
  1094.         me ~= CharacterThing(SysAdmin)
  1095.     then
  1096.         Print("The owner of that location has locked it.\n");
  1097.         false
  1098.     elif DoPlayerLeaveChecks(me, dir) ~= fail and
  1099.         DoChecks(here@(DirChecks(dir))) ~= fail and
  1100.         DoRoomAnyLeaveChecks(here) ~= fail
  1101.     then
  1102.         /* nothing was blocking the exit, nothing abnormal happened
  1103.            when we tried to go through, and nothing funny like player
  1104.            being chained to the floor */
  1105.         EnterRoom(dest, dir, MOVE_NORMAL)
  1106.     else
  1107.         false
  1108.     fi
  1109.     fi
  1110. corp;
  1111.  
  1112. ForwardReference@pDoMove := DoMove.
  1113.  
  1114. /*
  1115.  * UserMove - the user is explicitly moving.
  1116.  */
  1117.  
  1118. define t_util proc UserMove(int dir)bool:
  1119.  
  1120.     UnFollow();
  1121.     DoMove(dir)
  1122. corp;
  1123.  
  1124. /*
  1125.  * TryToMove - similar to 'DoMove', but intended for machines.
  1126.  *    Returns 'true' if it can do the move.
  1127.  *    Note: intended only for calling by the machine doing the moving.
  1128.  */
  1129.  
  1130. define t_util proc public TryToMove(int dir)bool:
  1131.     thing here, there, me;
  1132.  
  1133.     here := Here();
  1134.     me := Me();
  1135.     there := here@(DirProp(dir));
  1136.     if there = nil then
  1137.     false
  1138.     else
  1139.     not there@p_rNoMachines and not there@p_rLocked and
  1140.         me@p_pPosition = POS_NONE and
  1141.         DoPlayerLeaveChecks(me, dir) ~= fail and
  1142.         DoChecks(here@(DirChecks(dir))) ~= fail and
  1143.         DoRoomAnyLeaveChecks(here) ~= fail
  1144.     fi
  1145. corp;
  1146.  
  1147. /*
  1148.  * MachineMove - do the other half of 'DoMove' for machines. This does NOT
  1149.  *    use any of the exit checkers. It should be used with 'TryToMove',
  1150.  *    and not by itself.
  1151.  *    Note: intended only to be called by the machine doing the move.
  1152.  */
  1153.  
  1154. define t_util proc public MachineMove(int dir)void:
  1155.     thing here, me, dest;
  1156.     string myName, s;
  1157.     bool otherLight, meLight;
  1158.  
  1159.     here := Here();
  1160.     me := Me();
  1161.     myName := FormatName(me@p_pName);
  1162.     dest := here@(DirProp(dir));
  1163.     if dest ~= nil then
  1164.     meLight := me@p_oLight or FindFlagOnList(me@p_pCarrying, p_oLight);
  1165.     otherLight := LightAt(here);
  1166.     if otherLight or meLight then
  1167.         if not me@p_pHidden then
  1168.         s := here@(DirOMessage(dir));
  1169.         if s = "" then
  1170.             OPrint(myName + " has left to " + DirName(dir) + ".\n");
  1171.         elif s ~= "." then
  1172.             OPrint(myName + " " + s + "\n");
  1173.         fi;
  1174.         CheckFollowers(here, dir);
  1175.         fi;
  1176.         if not otherLight then
  1177.         ForEachAgent(here, UnShowRoomFromAgent);
  1178.         else
  1179.         /* we keep this in case it went hidden while here */
  1180.         ForEachAgent(here, UnShowIconOnce);
  1181.         fi;
  1182.     fi;
  1183.     /* The following is a subset of EnterRoom. It is cheaper, since the
  1184.        machine doesn't have to be told about the room and what and who
  1185.        is in it. */
  1186.     SetLocation(nil);
  1187.     otherLight := LightAt(dest);
  1188.     SetLocation(dest);
  1189.     if otherLight or meLight then
  1190.         dir := DirBack(dir);
  1191.         s := dest@(DirEMessage(dir));
  1192.         if s = "" then
  1193.         OPrint(myName + " has arrived from " + DirName(dir) + ".\n");
  1194.         elif s ~= "." then
  1195.         OPrint(myName + " " + s + "\n");
  1196.         fi;
  1197.         if not otherLight then
  1198.         ForEachAgent(dest, ShowRoomToAgent);
  1199.         else
  1200.         ForEachAgent(dest, ShowIconOnce);
  1201.         fi;
  1202.     fi;
  1203.     /* allow monster gen, etc. */
  1204.     ignore DoPlayerEnterChecks(me);
  1205.     /* allow for funny things like instant teleports out, etc. */
  1206.     ignore DoRoomAnyEnterChecks(dest);
  1207.     else
  1208.     OPrint("BUGGY MACHINE " + myName + " IS STUCK HERE.\n");
  1209.     fi;
  1210. corp;
  1211.  
  1212. /*
  1213.  * GetAgents - return a string which is a comma separated list of the
  1214.  *    names of the agents in the given room.
  1215.  */
  1216.  
  1217. define tp_util p_pAgentList CreateStringProp().
  1218.  
  1219. define tp_util proc addAnAgent(thing agent)void:
  1220.     thing me;
  1221.     string name, s;
  1222.  
  1223.     me := Me();
  1224.     name := agent@p_pName;
  1225.     if name ~= "" and not agent@p_pHidden then
  1226.     s := me@p_pAgentList;
  1227.     if s ~= "" then
  1228.         s := s + ", ";
  1229.     fi;
  1230.     s := s + FormatName(name);
  1231.     me@p_pAgentList := s;
  1232.     fi;
  1233. corp;
  1234.  
  1235. define t_util proc GetAgents(thing room)string:
  1236.     string s;
  1237.  
  1238.     ForEachAgent(room, addAnAgent);
  1239.     s := Me()@p_pAgentList;
  1240.     Me() -- p_pAgentList;
  1241.     s
  1242. corp;
  1243.  
  1244. /*
  1245.  * AddLight - introduce a source of light to the current room.
  1246.  */
  1247.  
  1248. define t_util proc public AddLight()void:
  1249.     if not CanSee(Here(), Me()) then
  1250.     ignore ShowRoomToMe(false);
  1251.     ForEachAgent(Here(), ShowRoomToAgent);
  1252.     fi;
  1253. corp;
  1254.  
  1255. /*
  1256.  * ActiveLightObject - an object is made to now emit light.
  1257.  */
  1258.  
  1259. define t_util proc public ActiveLightObject()status:
  1260.     thing it;
  1261.     string name;
  1262.  
  1263.     it := It();
  1264.     name := FormatName(it@p_oName);
  1265.     if it@p_oLight then
  1266.     Print("The " + name + " is already lit.\n");
  1267.     fail
  1268.     else
  1269.     Print("You light the " + name + ".\n");
  1270.     OPrint(Me()@p_pName + AAn(" lights", name) + ".\n");
  1271.     AddLight();
  1272.     it@p_oLight := true;
  1273.     /* want these to be succeed to allow proper use with VerbHere, etc. */
  1274.     succeed
  1275.     fi
  1276. corp;
  1277.  
  1278. /*
  1279.  * RemoveLight - remove a source of light from the current room.
  1280.  */
  1281.  
  1282. define t_util proc public RemoveLight()void:
  1283.     if not CanSee(Here(), Me()) then
  1284.     UnShowRoomFromMe();
  1285.     ForEachAgent(Here(), UnShowRoomFromAgent);
  1286.     fi;
  1287. corp;
  1288.  
  1289. /*
  1290.  * ActiveUnLightObject - an object is made to no longer emit light.
  1291.  */
  1292.  
  1293. define t_util proc public ActiveUnLightObject()status:
  1294.     thing it;
  1295.     string name;
  1296.  
  1297.     it := It();
  1298.     name := FormatName(it@p_oName);
  1299.     if not it@p_oLight then
  1300.     Print("The " + name + " is not lit.\n");
  1301.     fail
  1302.     else
  1303.     Print("You extinguish the " + name + ".\n");
  1304.     it@p_oLight := false;
  1305.     RemoveLight();
  1306.     succeed
  1307.     fi
  1308. corp;
  1309.  
  1310. /*
  1311.  * PassiveUnLightObject - an object is going out, independent of any player.
  1312.  */
  1313.  
  1314. define t_util proc public PassiveUnLightObject(thing object)void:
  1315.     thing who, where;
  1316.     character ch;
  1317.  
  1318.     object@p_oLight := false;
  1319.     who := object@p_oCarryer;
  1320.     where := object@p_oWhere;
  1321.     if who ~= nil then
  1322.     SPrint(who, "Your " + FormatName(object@p_oName) + " has gone out.\n");
  1323.     ch := Character(who@p_pName);
  1324.     if ch ~= nil and CharacterThing(ch) = who then
  1325.         where := CharacterLocation(ch);
  1326.         if not LightAt(where) then
  1327.         ForEachAgent(where, UnShowRoomFromAgent);
  1328.         fi;
  1329.     fi;
  1330.     elif where ~= nil and not LightAt(where) then
  1331.     ForEachAgent(where, UnShowRoomFromAgent);
  1332.     fi;
  1333. corp;
  1334.  
  1335. /*
  1336.  * CarryItem - try to add an item to the carry list. If too many complain
  1337.  *    and return false, else add the item and return true.
  1338.  */
  1339.  
  1340. define t_util proc CarryItem(thing object)bool:
  1341.     thing me;
  1342.     list thing carrying;
  1343.  
  1344.     me := Me();
  1345.     carrying := me@p_pCarrying;
  1346.     if Count(carrying) >= MAX_CARRY then
  1347.     Print("You can't carry anything else.\n");
  1348.     false
  1349.     else
  1350.     AddTail(carrying, object);
  1351.     object@p_oCarryer := me;
  1352.     true
  1353.     fi
  1354. corp;
  1355.  
  1356. /*
  1357.  * GetDocument - get a long document - e.g. description, letter, etc.
  1358.  *    Callable by player or machine - will do nothing for a machine.
  1359.  *    There are some things to watch out for here. We want these routines
  1360.  *    to be 'utility' so that they can be used properly by the build code.
  1361.  */
  1362.  
  1363. define tp_util p_pOldDoc CreateStringProp().
  1364. define tp_util p_pTempString CreateStringProp().
  1365. define tp_util p_pSavePrompt CreateStringProp().
  1366. define tp_util p_pSaveAction CreateActionProp().
  1367. define tp_util p_pEndAction CreateActionProp().
  1368. define tp_util p_pSaveIdleAction CreateActionProp().
  1369. define tp_util p_pRawDocument CreateBoolProp().
  1370.  
  1371. define tp_util proc utility appendToDocument(string line)void:
  1372.     action endAction;
  1373.     thing me, letter;
  1374.     string s;
  1375.     int len;
  1376.  
  1377.     me := Me();
  1378.     s := me@p_pTempString;
  1379.     len := Length(s);
  1380.     if line = "." then
  1381.     ignore SetCharacterIdleAction(me@p_pSaveIdleAction);
  1382.     me -- p_pSaveIdleAction;
  1383.     if me@p_pSaveAction ~= nil then
  1384.         ignore SetCharacterInputAction(me@p_pSaveAction);
  1385.         me -- p_pSaveAction;
  1386.         ignore SetPrompt(me@p_pSavePrompt);
  1387.         me -- p_pSavePrompt;
  1388.     fi;
  1389.     me -- p_pTempString;
  1390.     me -- p_pOldDoc;
  1391.     endAction := me@p_pEndAction;
  1392.     me -- p_pEndAction;
  1393.     me -- p_pRawDocument;
  1394.     if len >= 4000 then
  1395.         Print("*** Warning - input may have been truncated. ***\n");
  1396.     fi;
  1397.     /* call this so that, e.g. a normal person using the build code can
  1398.        modify his own objects that are ts_readonly */
  1399.     call(endAction, void)(s);
  1400.     else
  1401.     if len >= 4000 then
  1402.         Print("*** Warning - input has been truncated. ***\n");
  1403.     else
  1404.         if me@p_pRawDocument then
  1405.         me@p_pTempString := s + line + "\n";
  1406.         else
  1407.         if line ~= "" then
  1408.             if s ~= "" then
  1409.             s := s + " ";
  1410.             fi;
  1411.             me@p_pTempString := s + line;
  1412.         fi;
  1413.         fi;
  1414.     fi;
  1415.     fi;
  1416. corp;
  1417.  
  1418. define tp_util proc utility docIdleAction()void:
  1419.     action a;
  1420.  
  1421.     a := Me()@p_pSaveIdleAction;
  1422.     Me()@p_pTempString := Me()@p_pOldDoc;
  1423.     appendToDocument(".");
  1424.     if a ~= nil then
  1425.     call(a, void)();
  1426.     fi;
  1427. corp;
  1428.  
  1429. define tp_util proc utility docEndAction(string s; bool ok)void:
  1430.  
  1431.     if ok then
  1432.     Me()@p_pTempString := s;
  1433.     else
  1434.     Me()@p_pTempString := Me()@p_pOldDoc;
  1435.     fi;
  1436.     appendToDocument(".");
  1437. corp;
  1438.  
  1439. define t_util proc utility GetDocument(string prompt, intro, oldDoc;
  1440.     action endAction; bool isRaw)bool:
  1441.     thing me;
  1442.     action oldAction;
  1443.  
  1444.     me := Me();
  1445.     if CanEdit() then
  1446.     if Editing() then
  1447.         Print("You are alreadying editing something!\n");
  1448.         false
  1449.     else
  1450.         me@p_pTempString := "";
  1451.         me@p_pEndAction := endAction;
  1452.         me@p_pRawDocument := isRaw;
  1453.         oldAction := SetCharacterIdleAction(docIdleAction);
  1454.         if oldAction ~= nil then
  1455.         me@p_pSaveIdleAction := oldAction;
  1456.         fi;
  1457.         me@p_pOldDoc := oldDoc;
  1458.         EditString(oldDoc, docEndAction, isRaw, intro);
  1459.         true
  1460.     fi
  1461.     else
  1462.     oldAction := SetCharacterInputAction(appendToDocument);
  1463.     if oldAction = nil then
  1464.         /* must have been a machine! */
  1465.         OPrint(FormatName(me@p_pName) + " is confused.\n");
  1466.         false
  1467.     else
  1468.         Print(intro +
  1469.         ". End with a line containing only a single period.\n");
  1470.         me@p_pTempString := "";
  1471.         me@p_pSavePrompt := SetPrompt("* " + prompt);
  1472.         me@p_pSaveAction := oldAction;
  1473.         me@p_pEndAction := endAction;
  1474.         me@p_pRawDocument := isRaw;
  1475.         oldAction := SetCharacterIdleAction(docIdleAction);
  1476.         if oldAction ~= nil then
  1477.         me@p_pSaveIdleAction := oldAction;
  1478.         fi;
  1479.         true
  1480.     fi
  1481.     fi
  1482. corp;
  1483.  
  1484. /*
  1485.  * GetCheckedDescription - variant which lets a routine of the callers handle
  1486.  *    each of the input lines.
  1487.  */
  1488.  
  1489. define t_util proc utility GetCheckedEnd()void:
  1490.     thing me;
  1491.  
  1492.     me := Me();
  1493.     ignore SetCharacterIdleAction(me@p_pSaveIdleAction);
  1494.     me -- p_pSaveIdleAction;
  1495.     ignore SetCharacterInputAction(me@p_pSaveAction);
  1496.     me -- p_pSaveAction;
  1497.     ignore SetPrompt(me@p_pSavePrompt);
  1498.     me -- p_pSavePrompt;
  1499. corp;
  1500.  
  1501. define tp_util proc utility checkedDescIdleAction()void:
  1502.     thing me;
  1503.     action a;
  1504.  
  1505.     me := Me();
  1506.     a := SetCharacterInputAction(me@p_pSaveAction);
  1507.     if a ~= nil then
  1508.     me -- p_pSaveAction;
  1509.     call(a, void)(".");
  1510.     fi;
  1511.     ignore SetPrompt(me@p_pSavePrompt);
  1512.     me -- p_pSavePrompt;
  1513.     a := me@p_pSaveIdleAction;
  1514.     if a ~= nil then
  1515.     me -- p_pSaveIdleAction;
  1516.     call(a, void)();
  1517.     fi;
  1518. corp;
  1519.  
  1520. define t_util proc utility GetCheckedDescription(string prompt;
  1521.     action lineHandler)bool:
  1522.     thing me;
  1523.     action oldAction;
  1524.  
  1525.     me := Me();
  1526.     oldAction := SetCharacterInputAction(lineHandler);
  1527.     if oldAction = nil then
  1528.     /* must have been a machine! */
  1529.     OPrint(FormatName(me@p_pName) + " is confused.\n");
  1530.     false
  1531.     else
  1532.     me@p_pSaveAction := oldAction;
  1533.     me@p_pSavePrompt := SetPrompt("* " + prompt);
  1534.     oldAction := SetCharacterIdleAction(checkedDescIdleAction);
  1535.     if oldAction ~= nil then
  1536.         me@p_pSaveIdleAction := oldAction;
  1537.     fi;
  1538.     true
  1539.     fi
  1540. corp;
  1541.  
  1542. /*
  1543.  * Paginate - paginate a string within the output screen size.
  1544.  */
  1545.  
  1546. define tp_util paginateThing CreateThing(nil).
  1547. define tp_util p_paginateParse CreateActionProp().
  1548. define tp_util p_pPaginateSetup CreateBoolProp().
  1549. define tp_util p_pPaginateString CreateStringProp().
  1550. define tp_util p_pPaginateLen CreateIntProp().
  1551. define tp_util p_pPaginatePrompt CreateStringProp().
  1552. define tp_util p_pPaginateHandler CreateActionProp().
  1553. define tp_util p_pPaginateIdle CreateActionProp().
  1554.  
  1555. define tp_util proc paginateReset(bool goingIdle)void:
  1556.     thing me;
  1557.     action a;
  1558.  
  1559.     me := Me();
  1560.     me -- p_pPaginateString;
  1561.     me -- p_pPaginateLen;
  1562.     if me@p_pPaginateSetup then
  1563.     me -- p_pPaginateSetup;
  1564.     ignore SetPrompt(me@p_pPaginatePrompt);
  1565.     me -- p_pPaginatePrompt;
  1566.     ignore SetCharacterInputAction(me@p_pPaginateHandler);
  1567.     me -- p_pPaginateHandler;
  1568.     a := me@p_pPaginateIdle;
  1569.     me -- p_pPaginateIdle;
  1570.     ignore SetCharacterIdleAction(a);
  1571.     if goingIdle and a ~= nil then
  1572.         call(a, void)();
  1573.     fi;
  1574.     fi;
  1575. corp;
  1576.  
  1577. define tp_util proc paginateIdle()void:
  1578.     paginateReset(true);
  1579. corp;
  1580.  
  1581. define tp_util proc paginateShowPage()void:
  1582.     thing me;
  1583.     string s;
  1584.     int len, i, line, height, width;
  1585.  
  1586.     me := Me();
  1587.     s := me@p_pPaginateString;
  1588.     len := me@p_pPaginateLen;
  1589.     height := TextHeight(0) - 1;
  1590.     width := TextWidth(0);
  1591.     line := 1;
  1592.     while len > 0 and line <= height do
  1593.     i := Index(s, "\n");
  1594.     if i = -1 then
  1595.         Print(s);
  1596.         Print("\n");
  1597.         len := 0;
  1598.     else
  1599.         Print(SubString(s, 0, i + 1));
  1600.         s := SubString(s, i + 1, len - i - 1);
  1601.         len := len - i - 1;
  1602.         if i <= width then
  1603.         line := line + 1;
  1604.         else
  1605.         line := line + (i + width - 4) / (width - 9);
  1606.         fi;
  1607.     fi;
  1608.     od;
  1609.     if len = 0 then
  1610.     paginateReset(false);
  1611.     else
  1612.     me@p_pPaginateString := s;
  1613.     me@p_pPaginateLen := len;
  1614.     if not me@p_pPaginateSetup then
  1615.         me@p_pPaginateSetup := true;
  1616.         me@p_pPaginatePrompt := SetPrompt("[M O R E] ");
  1617.         me@p_pPaginateHandler :=
  1618.         SetCharacterInputAction(paginateThing@p_paginateParse);
  1619.         me@p_pPaginateIdle := SetCharacterIdleAction(paginateIdle);
  1620.     fi;
  1621.     fi;
  1622. corp;
  1623.  
  1624. define tp_util proc paginateParse(string line)void:
  1625.  
  1626.     if line = "" then
  1627.     paginateShowPage();
  1628.     elif line == "q" then
  1629.     paginateReset(false);
  1630.     else
  1631.     Print("Options are:\n  q - quit\n  empty line - next page\n");
  1632.     fi;
  1633. corp;
  1634.  
  1635. define t_util proc Paginate(string s)void:
  1636.     thing me;
  1637.  
  1638.     if GType(nil) == "amiga" then
  1639.     /* using full MUD client - no reason to paginate */
  1640.     Print(s);
  1641.     else
  1642.     me := Me();
  1643.     me@p_pPaginateString := s;
  1644.     me@p_pPaginateLen := Length(s);
  1645.     paginateShowPage();
  1646.     fi;
  1647. corp;
  1648.  
  1649. paginateThing@p_paginateParse := paginateParse.
  1650.  
  1651. /* code, etc. to assist/handle buying things in stores */
  1652.  
  1653. /* pre-create the lost and found room, so that we can set the 'home' of
  1654.    things that people buy */
  1655.  
  1656. define tp_misc r_lostAndFound CreateThing(r_indoors).
  1657. SetupRoom(r_lostAndFound, "in the lost and found room",
  1658.     "Things lost often end up here.").
  1659.  
  1660. /*
  1661.  * AddForSale - add an item for sale at the given location.
  1662.  *    Note: we WANT this one 'utility' so that it does not execute with
  1663.  *    SysAdmin privileges.
  1664.  */
  1665.  
  1666. define t_util proc utility public AddForSale(thing room; string name, desc;
  1667.     int price; action doBuy)thing:
  1668.     thing model;
  1669.     list thing lt;
  1670.  
  1671.     model := CreateThing(nil);
  1672.     SetThingStatus(model, ts_readonly);
  1673.     /* other players need to read it when shopping or buying */
  1674.     model@p_oName := name;
  1675.     if desc ~= "" then
  1676.     model@p_oDesc := desc;
  1677.     fi;
  1678.     model@p_oPrice := price;
  1679.     if doBuy ~= nil then
  1680.     model@p_oBuyChecker := doBuy;
  1681.     fi;
  1682.     model@p_oHome := r_lostAndFound;
  1683.     lt := room@p_rBuyList;
  1684.     if lt = nil then
  1685.     lt := CreateThingList();
  1686.     room@p_rBuyList := lt;
  1687.     fi;
  1688.     if FindElement(lt, model) = -1 then
  1689.     AddTail(lt, model);
  1690.     fi;
  1691.     model
  1692. corp;
  1693.  
  1694. /*
  1695.  * AddObjectForSale - make an already defined object be for sale.
  1696.  */
  1697.  
  1698. define t_util proc utility public AddObjectForSale(thing room, model;
  1699.     int price; action doBuy)void:
  1700.     list thing lt;
  1701.  
  1702.     model@p_oPrice := price;
  1703.     if doBuy ~= nil then
  1704.     model@p_oBuyChecker := doBuy;
  1705.     fi;
  1706.     lt := room@p_rBuyList;
  1707.     if lt = nil then
  1708.     lt := CreateThingList();
  1709.     room@p_rBuyList := lt;
  1710.     fi;
  1711.     if FindElement(lt, model) = -1 then
  1712.     AddTail(lt, model);
  1713.     fi;
  1714. corp;
  1715.  
  1716. /*
  1717.  * SubObjectForSale - make an object no longer for sale.
  1718.  */
  1719.  
  1720. define t_util proc utility public SubObjectForSale(thing room, model)bool:
  1721.     list thing lt;
  1722.  
  1723.     lt := room@p_rBuyList;
  1724.     if lt ~= nil then
  1725.     if FindElement(lt, model) ~= -1 then
  1726.         DelElement(lt, model);
  1727.         model -- p_oPrice;
  1728.         model -- p_oBuyChecker;
  1729.         true
  1730.     else
  1731.         false
  1732.     fi
  1733.     else
  1734.     false
  1735.     fi
  1736. corp;
  1737.  
  1738. /*
  1739.  * ShowForSale - show the things for sale at a player's current location.
  1740.  */
  1741.  
  1742. define t_util proc public ShowForSale()void:
  1743.     list thing lt;
  1744.     int count, n, price;
  1745.     thing model;
  1746.  
  1747.     lt := Here()@p_rBuyList;
  1748.     if lt = nil then
  1749.     Print("There is nothing for sale here.\n");
  1750.     else
  1751.     if not Me()@p_pHidden then
  1752.         OPrint(FormatName(Me()@p_pName) + " examines the merchandise.\n");
  1753.     fi;
  1754.     Print("For sale here:\n");
  1755.     count := Count(lt);
  1756.     n := 0;
  1757.     while n ~= count do
  1758.         model := lt[n];
  1759.         Print(FormatName(model@p_oName));
  1760.         Print(" - ");
  1761.         price := model@p_oPrice;
  1762.         if price = 0 then
  1763.         Print("free");
  1764.         elif price = 1 then
  1765.         Print("1 bluto");
  1766.         else
  1767.         IPrint(price);
  1768.         Print(" blutos");
  1769.         fi;
  1770.         Print("\n");
  1771.         n := n + 1;
  1772.     od;
  1773.     fi;
  1774. corp;
  1775.  
  1776. /*
  1777.  * StoreBuy - let the user buy something at a store. This is used as the
  1778.  *    'buy' action at the store location.
  1779.  *    Note: this is NOT a utility proc, since we want the object to
  1780.  *          be owned by SysAdmin, and since we use OPrint.
  1781.  *    Note: intended only to be called by the player doing the buy.
  1782.  *          Looks like it would work for machines too, however.
  1783.  */
  1784.  
  1785. define t_util proc public StoreBuy(string what)bool:
  1786.     thing here, model, me, th;
  1787.     string name;
  1788.     int price, money;
  1789.     action buyAction;
  1790.     status st;
  1791.  
  1792.     here := Here();
  1793.     if here@p_rBuyList = nil then
  1794.     Print("There is nothing for sale here.\n");
  1795.     false
  1796.     else
  1797.     name := FormatName(what);
  1798.     st := FindName(here@p_rBuyList, p_oName, what);
  1799.     if st = fail then
  1800.         Print(AAn("You cannot buy", name) + " here.\n");
  1801.         false
  1802.     elif st = continue then
  1803.         Print(name + " is ambiguous here.\n");
  1804.         false
  1805.     else
  1806.         model := FindResult();
  1807.         me := Me();
  1808.         price := model@p_oPrice;
  1809.         money := me@p_pMoney;
  1810.         name := FormatName(model@p_oName);
  1811.         if price > money and not me@p_pPrivileged then
  1812.         Print(AAn("You cannot afford", name) + ".\n");
  1813.         false
  1814.         else
  1815.         th := CreateThing(model);
  1816.         /* We want the thing public so that anyone can do things to
  1817.            it. ts_readonly would work not bad, but that prevents
  1818.            a builder from modifying it. We want it owned by SysAdmin
  1819.            so that all the code that is setuid SysAdmin has no
  1820.            trouble with it. We have to do the SetThingStatus BEFORE
  1821.            we give it away, else we will not have access to do so. */
  1822.         SetThingStatus(th, ts_public);
  1823.         GiveThing(th, SysAdmin);
  1824.         if model@p_oContents ~= nil then
  1825.             th@p_oContents := CreateThingList();
  1826.         fi;
  1827.         th@p_oCreator := me;
  1828.         buyAction := model@p_oBuyChecker;
  1829.         st := continue;
  1830.         if buyAction ~= nil then
  1831.             SetIt(th);
  1832.             st := call(buyAction, status)();
  1833.         fi;
  1834.         if st ~= fail and CarryItem(th) then
  1835.             if not me@p_pPrivileged then
  1836.             me@p_pMoney := money - price;
  1837.             fi;
  1838.             if st = continue then
  1839.             Print(AAn("You have just bought", name) + ".\n");
  1840.             if not me@p_pHidden then
  1841.                 OPrint(FormatName(me@p_pName) +
  1842.                    " makes a purchase.\n");
  1843.             fi;
  1844.             fi;
  1845.         else
  1846.             ClearThing(th);
  1847.         fi;
  1848.         true
  1849.         fi
  1850.     fi
  1851.     fi
  1852. corp;
  1853.  
  1854. /*
  1855.  * MakeStore - make a room a store.
  1856.  */
  1857.  
  1858. define t_util proc utility public MakeStore(thing room)void:
  1859.  
  1860.     room@p_rBuyAction := StoreBuy;
  1861. corp;
  1862.  
  1863. /*
  1864.  * IsStore - ask if room is a store.
  1865.  */
  1866.  
  1867. define t_util proc utility public IsStore(thing room)bool:
  1868.  
  1869.     room@p_rBuyAction = StoreBuy
  1870. corp;
  1871.  
  1872. /*
  1873.  * UnmakeStore - make a room no longer a store.
  1874.  */
  1875.  
  1876. define t_util proc utility public UnmakeStore(thing room)void:
  1877.  
  1878.     room -- p_rBuyList;
  1879.     room -- p_rBuyAction;
  1880. corp;
  1881.  
  1882. /*
  1883.  * AddSpecialCommand - set things up to add a special this-room-only
  1884.  *    command. Note: allowing the use of this procedure is a fairly large
  1885.  *    security hole, since the commands thus added take precedence OVER
  1886.  *    the normal ones, thus this routine can be used to invoke arbitrary
  1887.  *    action when a player uses a presumed safe command. See 'parseInput'
  1888.  *    for the actual use of these values.
  1889.  */
  1890.  
  1891. define tp_util p_rSpecialWords CreateStringProp().
  1892. define tp_util p_rSpecialActions CreateActionListProp().
  1893.  
  1894. define t_util proc utility public AddSpecialCommand(thing room; string command;
  1895.     action a)void:
  1896.     list action la;
  1897.  
  1898.     la := room@p_rSpecialActions;
  1899.     if la = nil then
  1900.     la := CreateActionList();
  1901.     room@p_rSpecialActions := la;
  1902.     fi;
  1903.     room@p_rSpecialWords := room@p_rSpecialWords + command + ".";
  1904.     AddTail(la, a);
  1905. corp;
  1906.  
  1907. define t_util proc utility public RemoveSpecialCommand(thing room;
  1908.     string command; action a)bool:
  1909.     list action la;
  1910.     string s;
  1911.     int pos, len;
  1912.  
  1913.     la := room@p_rSpecialActions;
  1914.     if la ~= nil then
  1915.     s := room@p_rSpecialWords;
  1916.     command := command + ".";
  1917.     pos := Index(s, command);
  1918.     if pos ~= -1 then
  1919.         len := Length(command);
  1920.         room@p_rSpecialWords := SubString(s, 0, pos) +
  1921.         SubString(s, pos + len, Length(s) - pos - len);
  1922.         DelElement(la, a);
  1923.         true
  1924.     else
  1925.         false
  1926.     fi
  1927.     else
  1928.     false
  1929.     fi
  1930. corp;
  1931.  
  1932. /*
  1933.  * DoSay - bottom level of saying - here since 'parseInput' uses it.
  1934.  *    Needs to be not 'utility' in order to use 'Say'.
  1935.  */
  1936.  
  1937. define t_util proc public DoSay(string what)void:
  1938.     thing me, here;
  1939.  
  1940.     here := Here();
  1941.     if DoRoomSayChecks(here, what) = continue then
  1942.     me := Me();
  1943.     if me@p_pEchoPose then
  1944.         Print("You say: " + what + "\n");
  1945.     fi;
  1946.     Say(if me@p_pHidden or not CanSee(me, here) then "Someone" else "" fi,
  1947.         what);
  1948.     fi;
  1949. corp;
  1950.  
  1951. /*
  1952.  * checkAlias - check for and handle an alias on the character. This is
  1953.  *    a separate routine so that it is NOT 'utility', but is owned by
  1954.  *    SysAdmin. This lets folks other than SysAdmin read the alias
  1955.  *    things!
  1956.  */
  1957.  
  1958. define tp_util proc checkAlias(string s)string:
  1959.     list thing aliases;
  1960.     thing alias;
  1961.     string word;
  1962.     int count;
  1963.     bool doneIt;
  1964.  
  1965.     SetTail(s);
  1966.     word := GetWord();
  1967.     aliases := Me()@p_pAliases;
  1968.     if aliases ~= nil then
  1969.     count := Count(aliases);
  1970.     doneIt := false;
  1971.     while count ~= 0 and not doneIt do
  1972.         count := count - 1;
  1973.         alias := aliases[count];
  1974.         if alias@p_sAliasKey == word then
  1975.         s := alias@p_sAliasValue + " " + GetTail();
  1976.         doneIt := true;
  1977.         fi;
  1978.     od;
  1979.     fi;
  1980.     s
  1981. corp;
  1982.  
  1983. /*
  1984.  * parseInput - the normal input command handler.
  1985.  *    NOTE: we want this to be 'utility', so that the build commands can
  1986.  *    be run by the real player. The problem with this is that any message
  1987.  *    from 'Parse' will have an '@' in front if it is run by a non-wizard.
  1988.  *    I'll kluge that by having 'Parse' force wizard-mode if it needs to
  1989.  *    print an error message. Sigh.
  1990.  *    Another '@' problem surfaces: if the whole result of the user command
  1991.  *    is to print a 'p_oActString', then that output will be prefixed with
  1992.  *    '@' when a non-wizard is running. I have implemented 'NPrint' to
  1993.  *    hopefully get around this.
  1994.  */
  1995.  
  1996. define tp_util proc utility parseInput(string s)void:
  1997.     action a;
  1998.     thing here, it, me;
  1999.     string word, specials;
  2000.     int which, count;
  2001.     bool doneIt;
  2002.  
  2003.     if s ~= "" then
  2004.     if SubString(s, 0, 1) = "\"" then
  2005.         DoSay(SubString(s, 1, Length(s) - 1));
  2006.     else
  2007.         here := Here();
  2008.         me := Me();
  2009.         s := checkAlias(s);
  2010.         SetTail(s);
  2011.         word := GetWord();
  2012.         if FindName(me@p_pCarrying, p_oActWord, word) = fail and
  2013.         FindName(here@p_rContents, p_oActWord, word) = fail
  2014.         then
  2015.         doneIt := false;
  2016.         specials := here@p_rSpecialWords;
  2017.         if specials ~= "" then
  2018.             which := MatchName(specials, word);
  2019.             if which >= 0 then
  2020.             call(here@p_rSpecialActions[which], void)();
  2021.             doneIt := true;
  2022.             fi;
  2023.         fi;
  2024.         if not doneIt then
  2025.             /* most commands are done right here */
  2026.             ignore Parse(G, s);
  2027.         fi;
  2028.         else
  2029.         it := FindResult();
  2030.         a := it@p_oActAction;
  2031.         if a ~= nil then
  2032.             SetIt(it);
  2033.             call(a, void)();
  2034.         else
  2035.             NPrint(it@p_oActString);
  2036.         fi;
  2037.         fi;
  2038.     fi;
  2039.     fi;
  2040. corp;
  2041.  
  2042. /*
  2043.  * define constants for the various raw-key codes.
  2044.  */
  2045.  
  2046. define t_util KEY_HELP        0x0020.
  2047. define t_util KEY_KP_UL     0x0001.
  2048. define t_util KEY_KP_U        0x0002.
  2049. define t_util KEY_KP_UR     0x0003.
  2050. define t_util KEY_KP_L        0x0004.
  2051. define t_util KEY_KP_C        0x0005.
  2052. define t_util KEY_KP_R        0x0006.
  2053. define t_util KEY_KP_DL     0x0007.
  2054. define t_util KEY_KP_D        0x0008.
  2055. define t_util KEY_KP_DR     0x0009.
  2056. define t_util KEY_KP_PLUS    0x000a.
  2057. define t_util KEY_KP_MINUS    0x000b.
  2058.  
  2059. /*
  2060.  * handleRawKey - handle a raw special key-hit.
  2061.  *    We want this routine NOT utility, so that there is not an '@' in
  2062.  *    front of the command when 'InsertCommand' prints it.
  2063.  */
  2064.  
  2065. define tp_util proc handleRawKey(int n)void:
  2066.  
  2067.     case n
  2068.     incase KEY_HELP:
  2069.     InsertCommand("help");
  2070.     incase KEY_KP_UL:
  2071.     InsertCommand("northwest");
  2072.     incase KEY_KP_U:
  2073.     InsertCommand("north");
  2074.     incase KEY_KP_UR:
  2075.     InsertCommand("northeast");
  2076.     incase KEY_KP_L:
  2077.     InsertCommand("west");
  2078.     incase KEY_KP_C:
  2079.     InsertCommand("look");
  2080.     incase KEY_KP_R:
  2081.     InsertCommand("east");
  2082.     incase KEY_KP_DL:
  2083.     InsertCommand("southwest");
  2084.     incase KEY_KP_D:
  2085.     InsertCommand("south");
  2086.     incase KEY_KP_DR:
  2087.     InsertCommand("southeast");
  2088.     incase KEY_KP_PLUS:
  2089.     InsertCommand("up");
  2090.     incase KEY_KP_MINUS:
  2091.     InsertCommand("down");
  2092.     esac;
  2093. corp;
  2094.  
  2095. /*
  2096.  * idleAction - the action that is executed when the player leaves.
  2097.  *    These are NOT utility - do not want '@' in front of any output.
  2098.  */
  2099.  
  2100. define tp_util proc idleAction()void:
  2101.     thing here;
  2102.  
  2103.     here := Here();
  2104.     SetLocation(nil);
  2105.     if LightAt(here) then
  2106.     ForEachAgent(here, UnShowIconOnce);
  2107.     else
  2108.     if HasLight(Me()) then
  2109.         ForEachAgent(here, UnShowRoomFromAgent);
  2110.     fi;
  2111.     fi;
  2112.     SetLocation(here);
  2113.     Me()@p_MapGroup := NO_MAP_GROUP;
  2114.     Me()@p_pStandardGraphicsDone := false;
  2115.     OPrint(Me()@p_pName + " has exited the world.\n");
  2116. corp;
  2117.  
  2118. /*
  2119.  * activeAction - the action that is executed when the player re-enters.
  2120.  */
  2121.  
  2122. define tp_util proc activeAction()void:
  2123.     thing here, me;
  2124.  
  2125.     here := Here();
  2126.     me := Me();
  2127.     if GOn(nil) then
  2128.     GSetTextColour(nil, 0, me@p_pTextColours[0]);
  2129.     GSetTextColour(nil, 1, me@p_pTextColours[1]);
  2130.     GSetTextColour(nil, 2, me@p_pTextColours[2]);
  2131.     GSetTextColour(nil, 3, me@p_pTextColours[3]);
  2132.     InitStandardGraphics();
  2133.     else
  2134.     me@p_pStandardGraphicsDone := false;
  2135.     fi;
  2136.     DoList(me@p_pEnterActions);
  2137.     ignore Parse(G, "look around");
  2138.     ignore ShowClients(false);
  2139.     SetLocation(nil);
  2140.     if LightAt(here) then
  2141.     SetLocation(here);
  2142.     ForEachAgent(here, ShowIconOnce);
  2143.     else
  2144.     SetLocation(here);
  2145.     if HasLight(me) then
  2146.         ForEachAgent(here, ShowRoomToAgent);
  2147.     fi;
  2148.     fi;
  2149.     OPrint(me@p_pName + " has entered the world.\n");
  2150. corp;
  2151.  
  2152. /* Some stuff to implement banks. Note that these properties are private,
  2153.    so no-one else can change bank accounts. Note also that the routines are
  2154.    NOT utility routines, since we want the things created to represent the
  2155.    accounts to not be owned by the player. */
  2156.  
  2157. define tp_util p_rBankAccounts CreateThingListProp().    /* bank account list */
  2158. define tp_util p_oAccountValue CreateIntProp().     /* value in account */
  2159. define tp_util p_oAccountOwner CreateThingProp().    /* who owns account */
  2160.  
  2161. define tp_util proc bankDeposit()void:
  2162.     list thing lt;
  2163.     int money, amount, count, i;
  2164.     thing me, account;
  2165.     string st;
  2166.  
  2167.     st := GetWord();
  2168.     if st = "" then
  2169.     Print("You must say how many blutos you wish to deposit.\n");
  2170.     else
  2171.     amount := StringToPosInt(st);
  2172.     if amount < 0 then
  2173.         Print("Invalid amount - must be a number.\n");
  2174.     else
  2175.         lt := Here()@p_rBankAccounts;
  2176.         if lt = nil then
  2177.         Print("*** no account list found ***\n");
  2178.         else
  2179.         me := Me();
  2180.         money := me@p_pMoney;
  2181.         if amount > money then
  2182.             Print("You do not have that much money on you.\n");
  2183.         else
  2184.             count := Count(lt);
  2185.             i := 0;
  2186.             while
  2187.             if i = count then
  2188.                 false
  2189.             else
  2190.                 account := lt[i];
  2191.                 account@p_oAccountOwner ~= me
  2192.             fi
  2193.             do
  2194.             i := i + 1;
  2195.             od;
  2196.             if i = count then
  2197.             Print("Setting up a new account for \"");
  2198.             Print(me@p_pName);
  2199.             Print("\". ");
  2200.             account := CreateThing(nil);
  2201.             account@p_oAccountOwner := me;
  2202.             AddTail(lt, account);
  2203.             i := 0;
  2204.             else
  2205.             i := account@p_oAccountValue;
  2206.             fi;
  2207.             me@p_pMoney := money - amount;
  2208.             amount := amount + i;
  2209.             account@p_oAccountValue := amount;
  2210.             Print("Thank you for your deposit. Your account now has "
  2211.             "a balance of ");
  2212.             if amount = 1 then
  2213.             Print("one bluto.\n");
  2214.             else
  2215.             IPrint(amount);
  2216.             Print(" blutos.\n");
  2217.             fi;
  2218.             if not me@p_pHidden and CanSee(Here(), me) then
  2219.             OPrint(FormatName(me@p_pName) +
  2220.                 " makes a transaction.\n");
  2221.             fi;
  2222.         fi;
  2223.         fi;
  2224.     fi;
  2225.     fi;
  2226. corp;
  2227.  
  2228. define tp_util proc bankWithdraw()void:
  2229.     list thing lt;
  2230.     int amount, count, i;
  2231.     thing me, account;
  2232.     string st;
  2233.  
  2234.     st := GetWord();
  2235.     if st = "" then
  2236.     Print("You must say how many blutos you wish to withdraw.\n");
  2237.     else
  2238.     amount := StringToPosInt(st);
  2239.     if amount < 0 then
  2240.         Print("Invalid amount - must be a number.\n");
  2241.     else
  2242.         lt := Here()@p_rBankAccounts;
  2243.         if lt = nil then
  2244.         Print("*** no account list found ***\n");
  2245.         else
  2246.         me := Me();
  2247.         count := Count(lt);
  2248.         i := 0;
  2249.         while
  2250.             if i = count then
  2251.             false
  2252.             else
  2253.             account := lt[i];
  2254.             account@p_oAccountOwner ~= me
  2255.             fi
  2256.         do
  2257.             i := i + 1;
  2258.         od;
  2259.         if i = count then
  2260.             Print("I'm sorry, this bank has no account for \"");
  2261.             Print(me@p_pName);
  2262.             Print("\".\n");
  2263.         else
  2264.             i := account@p_oAccountValue;
  2265.             if amount > i then
  2266.             Print("I'm sorry, you do not have that much in "
  2267.                 "your account.\n");
  2268.             else
  2269.             me@p_pMoney := me@p_pMoney + amount;
  2270.             amount := i - amount;
  2271.             account@p_oAccountValue := amount;
  2272.             if amount = 0 then
  2273.                 Print("Withdrawal made. Your account is now "
  2274.                   "empty and has been closed.\n");
  2275.                 ClearThing(account);
  2276.                 DelElement(lt, account);
  2277.             else
  2278.                 Print("Withdrawal made. Your account now has a "
  2279.                 "balance of ");
  2280.                 if amount = 1 then
  2281.                 Print("one bluto.\n");
  2282.                 else
  2283.                 IPrint(amount);
  2284.                 Print(" blutos.\n");
  2285.                 fi;
  2286.             fi;
  2287.             fi;
  2288.             if not me@p_pHidden and CanSee(Here(), me) then
  2289.             OPrint(FormatName(me@p_pName) +
  2290.                 " makes a transaction.\n");
  2291.             fi;
  2292.         fi;
  2293.         fi;
  2294.     fi;
  2295.     fi;
  2296. corp;
  2297.  
  2298. define tp_util proc bankBalance()void:
  2299.     list thing lt;
  2300.     int amount, count, i;
  2301.     thing me, account;
  2302.  
  2303.     lt := Here()@p_rBankAccounts;
  2304.     if lt = nil then
  2305.     Print("*** no account list found ***\n");
  2306.     else
  2307.     me := Me();
  2308.     count := Count(lt);
  2309.     i := 0;
  2310.     while
  2311.         if i = count then
  2312.         false
  2313.         else
  2314.         account := lt[i];
  2315.         account@p_oAccountOwner ~= me
  2316.         fi
  2317.     do
  2318.         i := i + 1;
  2319.     od;
  2320.     if i = count then
  2321.         Print("I'm sorry, this bank has no account for \"");
  2322.         Print(me@p_pName);
  2323.         Print("\".\n");
  2324.     else
  2325.         amount := account@p_oAccountValue;
  2326.         Print("Your account has a balance of ");
  2327.         if amount = 1 then
  2328.         Print("one bluto.\n");
  2329.         else
  2330.         IPrint(amount);
  2331.         Print(" blutos.\n");
  2332.         fi;
  2333.         if not me@p_pHidden and CanSee(Here(), me) then
  2334.         OPrint(FormatName(me@p_pName) + " makes a transaction.\n");
  2335.         fi;
  2336.     fi;
  2337.     fi;
  2338. corp;
  2339.  
  2340. /*
  2341.  * make this one utility, so people can only do it to their own rooms.
  2342.  */
  2343.  
  2344. define t_util proc utility public MakeBank(thing room)void:
  2345.  
  2346.     room@p_rBankAccounts := CreateThingList();
  2347.     AddSpecialCommand(room, "deposit", bankDeposit);
  2348.     AddSpecialCommand(room, "withdraw", bankWithdraw);
  2349.     AddSpecialCommand(room, "balance", bankBalance);
  2350. corp;
  2351.  
  2352. define t_util proc utility public IsBank(thing room)bool:
  2353.  
  2354.     room@p_rBankAccounts ~= nil
  2355. corp;
  2356.  
  2357. define t_util proc utility public UnmakeBank(thing room)status:
  2358.     list thing accounts;
  2359.  
  2360.     accounts := room@p_rBankAccounts;
  2361.     if accounts = nil then
  2362.     continue
  2363.     elif Count(accounts) ~= 0 then
  2364.     fail
  2365.     else
  2366.     room -- p_rBankAccounts;
  2367.     ignore RemoveSpecialCommand(room, "deposit", bankDeposit);
  2368.     ignore RemoveSpecialCommand(room, "withdraw", bankWithdraw);
  2369.     ignore RemoveSpecialCommand(room, "balance", bankBalance);
  2370.     succeed
  2371.     fi
  2372. corp;
  2373.  
  2374. /* a couple of handy utilities */
  2375.  
  2376. define t_util proc isYes(string s)bool:
  2377.  
  2378.     s == "y" or s == "yes" or s == "t" or s == "true"
  2379. corp;
  2380.  
  2381. define t_util proc isNo(string s)bool:
  2382.  
  2383.     s == "n" or s == "no" or s == "n" or s == "false"
  2384. corp;
  2385.  
  2386. /* Some general routines for setting up verbs that do things to things.
  2387.    'VerbCarry' requires that the player be carrying the object in order to
  2388.    do whatever to it. 'VerbHere' allows it to be either carried or in the
  2389.    room the player is in. It would also be possible to look at things that
  2390.    are carried by other players/machines, but I chose not to. Note that
  2391.    I check the player, then the room, then the specific object.
  2392.    Return 'false' if we were not able to do the action on the requested
  2393.    thing, because the thing is not available, or the action fails.
  2394. */
  2395.  
  2396. /* A problem has cropped up with the drinking monsters. The code below
  2397.    looks for the same properties on the player, the room and the object.
  2398.    So, if you try to drink the drinking troll, it will execute the drink
  2399.    action on the troll and say that you shouldn't do that. Unfortunately,
  2400.    that action is also done when the troll's special action gets the troll
  2401.    to 'drink water'. Proper solution is two more properties, sigh. This
  2402.    has been done for the indirect case with 'actorCheck'. Thus we do not
  2403.    allow the case of attaching a string to the player which is the entire
  2404.    result of trying to do that action. */
  2405.  
  2406. define t_util proc public commonVerbTail(property string direct;
  2407.     property action indirect, actorCheck; thing object;
  2408.     string failHeader, verbName, name)bool:
  2409.     thing me, here;
  2410.     action a;
  2411.     string directString;
  2412.     status st;
  2413.     bool doneOne;
  2414.  
  2415.     /* Note: the status values returned by the handler routines are
  2416.        interpreted as follows:
  2417.       continue - nothing special - keep looking for something special
  2418.       succeed - successfully handled this case
  2419.       fail - this case is handled, but cease cases and parsing
  2420.        The presence of a 'direct' string property is taken to be the same
  2421.        as a routine which prints that string and returns 'succeed', with
  2422.        the exception that something on a given object will override a
  2423.        direct string on a location.
  2424.     */
  2425.  
  2426.     me := Me();
  2427.     here := Here();
  2428.     doneOne := false;
  2429.     if actorCheck ~= nil then
  2430.     a := me@actorCheck;
  2431.     if a ~= nil then
  2432.         SetIt(object);
  2433.         st := call(a, status)();
  2434.         if st ~= continue then
  2435.         doneOne := true;
  2436.         fi;
  2437.     fi;
  2438.     fi;
  2439.     if not doneOne and indirect ~= nil then
  2440.     a := here@indirect;
  2441.     if a ~= nil then
  2442.         SetIt(object);
  2443.         st := call(a, status)();
  2444.         if st ~= continue then
  2445.         doneOne := true;
  2446.         fi;
  2447.     fi;
  2448.     fi;
  2449.     if not doneOne and direct ~= nil then
  2450.     directString := here@direct;
  2451.     if directString ~= "" and
  2452.         (object = nil or object@direct = "" and object@indirect = nil)
  2453.     then
  2454.         doneOne := true;
  2455.         Print(directString + "\n");
  2456.         st := continue;
  2457.     fi;
  2458.     fi;
  2459.     if not doneOne and object ~= nil and indirect ~= nil then
  2460.     a := object@indirect;
  2461.     if a ~= nil then
  2462.         SetIt(object);
  2463.         st := call(a, status)();
  2464.         if st ~= continue then
  2465.         doneOne := true;
  2466.         fi;
  2467.     fi;
  2468.     fi;
  2469.     if not doneOne and object ~= nil and direct ~= nil then
  2470.     directString := object@direct;
  2471.     if directString ~= "" then
  2472.         doneOne := true;
  2473.         Print(directString + "\n");
  2474.         st := continue;
  2475.     fi;
  2476.     fi;
  2477.     if doneOne then
  2478.     st ~= fail
  2479.     elif object = nil then
  2480.     Print("You must specify what you want to " + verbName + ".\n");
  2481.     false
  2482.     else
  2483.     Print(failHeader + " the " + name + ".\n");
  2484.     true
  2485.     fi
  2486. corp;
  2487.  
  2488. define t_util proc public VerbCarry(string verbName; property string direct;
  2489.     property action indirect, actorCheck; string failHeader, what)bool:
  2490.     thing object;
  2491.     string name;
  2492.     status st;
  2493.     bool done, ok;
  2494.     list thing lt;
  2495.     int i, count, oldCount;
  2496.  
  2497.     done := false;
  2498.     if what = "" then
  2499.     object := nil;
  2500.     elif what == "all" then
  2501.     lt := Me()@p_pCarrying;
  2502.     count := Count(lt);
  2503.     i := 0;
  2504.     ok := true;
  2505.     while ok and i ~= count do
  2506.         object := lt[i];
  2507.         if not object@p_oInvisible then
  2508.         done := true;
  2509.         if commonVerbTail(direct, indirect, actorCheck,
  2510.             object, failHeader, verbName, FormatName(object@p_oName))
  2511.         then
  2512.             oldCount := count;
  2513.             count := Count(lt);
  2514.             i := i - (oldCount - count) + 1;
  2515.         else
  2516.             ok := false;
  2517.         fi;
  2518.         else
  2519.         i := i + 1;
  2520.         fi;
  2521.     od;
  2522.     if not done then
  2523.         done := true;
  2524.         Print("You are not carrying anything obvious to " + verbName +
  2525.           ".\n");
  2526.         ok := false;
  2527.     fi;
  2528.     else
  2529.     name := FormatName(what);
  2530.     st := FindName(Me()@p_pCarrying, p_oName, what);
  2531.     if st = fail then
  2532.         Print(AAn("You are not carrying", name) + ".\n");
  2533.         ok := false;
  2534.         done := true;
  2535.     elif st = continue then
  2536.         Print(name + " is ambiguous here.\n");
  2537.         ok := false;
  2538.         done := true;
  2539.     else
  2540.         object := FindResult();
  2541.     fi;
  2542.     fi;
  2543.     if done then
  2544.     ok
  2545.     else
  2546.     commonVerbTail(direct, indirect, actorCheck,
  2547.                object, failHeader, verbName, name)
  2548.     fi
  2549. corp;
  2550.  
  2551. define t_util proc public VerbHere(string verbName; property string direct;
  2552.     property action indirect, actorCheck; string failHeader, what)bool:
  2553.     thing here, object;
  2554.     list thing lt;
  2555.     int count, i, oldCount;
  2556.     string ambig, name;
  2557.     status st;
  2558.     bool done, ok;
  2559.  
  2560.     here := Here();
  2561.     done := false;
  2562.     object := nil;
  2563.     if what == "all" then
  2564.     lt := Me()@p_pCarrying;
  2565.     count := Count(lt);
  2566.     i := 0;
  2567.     ok := true;
  2568.     while ok and i ~= count do
  2569.         object := lt[i];
  2570.         if not object@p_oInvisible then
  2571.         done := true;
  2572.         if commonVerbTail(direct, indirect, actorCheck, object,
  2573.             failHeader, verbName, FormatName(object@p_oName))
  2574.         then
  2575.             oldCount := count;
  2576.             count := Count(lt);
  2577.             i := i - (oldCount - count) + 1;
  2578.         else
  2579.             ok := false;
  2580.         fi;
  2581.         else
  2582.         i := i + 1;
  2583.         fi;
  2584.     od;
  2585.     lt := here@p_rContents;
  2586.     count := Count(lt);
  2587.     i := 0;
  2588.     while ok and i ~= count do
  2589.         object := lt[i];
  2590.         if not object@p_oInvisible then
  2591.         done := true;
  2592.         if commonVerbTail(direct, indirect, actorCheck,
  2593.             object, failHeader, verbName, FormatName(object@p_oName))
  2594.         then
  2595.             oldCount := count;
  2596.             count := Count(lt);
  2597.             i := i - (oldCount - count) + 1;
  2598.         else
  2599.             ok := false;
  2600.         fi;
  2601.         else
  2602.         i := i + 1;
  2603.         fi;
  2604.     od;
  2605.     if not done then
  2606.         done := true;
  2607.         Print("There is nothing obvious here to " + verbName + ".\n");
  2608.         ok := false;
  2609.     fi;
  2610.     elif what ~= "" then
  2611.     name := FormatName(what);
  2612.     ambig := " is ambiguous here.\n";
  2613.     st := FindName(Me()@p_pCarrying, p_oName, what);
  2614.     if st = fail then
  2615.         st := FindName(here@p_rContents, p_oName, what);
  2616.         if st = fail then
  2617.         object := FindAgent(what);
  2618.         if object = nil then
  2619.             if MatchName(here@p_rScenery, what) ~= -1 then
  2620.             done := true;
  2621.             ok := false;
  2622.             Print(failHeader + " the " + name + ".\n");
  2623.             fi;
  2624.         fi;
  2625.         elif st = continue then
  2626.         Print(name);
  2627.         Print(ambig);
  2628.         ok := false;
  2629.         done := true;
  2630.         else
  2631.         object := FindResult();
  2632.         fi;
  2633.     elif st = continue then
  2634.         Print(name);
  2635.         Print(ambig);
  2636.         ok := false;
  2637.         done := true;
  2638.     else
  2639.         object := FindResult();
  2640.     fi;
  2641.     if object = nil and not done then
  2642.         Print(IsAre("There", "no", name, "here.\n"));
  2643.         done := true;
  2644.         ok := false;
  2645.     fi;
  2646.     fi;
  2647.     if done then
  2648.     ok
  2649.     else
  2650.     commonVerbTail(direct, indirect, actorCheck,
  2651.                object, failHeader, verbName, name)
  2652.     fi
  2653. corp;
  2654.  
  2655. /*
  2656.  * ResetObjects - go through a list of objects and put them back where they
  2657.  *    belong. This is useful for single-user-at-a-time quests.
  2658.  */
  2659.  
  2660. define t_util proc utility public ResetObjects(list thing lt)void:
  2661.     int count;
  2662.     thing object, home, now;
  2663.  
  2664.     count := Count(lt);
  2665.     while count ~= 0 do
  2666.     count := count - 1;
  2667.     object := lt[count];
  2668.     home := object@p_oHome;
  2669.     if home ~= nil then
  2670.         now := object@p_oWhere;
  2671.         if now ~= nil then
  2672.         if now ~= home then
  2673.             AddTail(home@p_rContents, object);
  2674.             if now@p_rContents ~= nil then
  2675.             DelElement(now@p_rContents, object);
  2676.             else
  2677.             DelElement(now@p_oContents, object);
  2678.             fi;
  2679.             object@p_oWhere := home;
  2680.         fi;
  2681.         else
  2682.         now := object@p_oCarryer;
  2683.         if now = nil then
  2684.             Print("An object being reset isn't anywhere!\n"
  2685.             "Please inform the owner of this quest.\n");
  2686.         else
  2687.             AddTail(home@p_rContents, object);
  2688.             DelElement(now@p_pCarrying, object);
  2689.             object -- p_oCarryer;
  2690.             object@p_oWhere := home;
  2691.             /* Specifically SPrint, so that other players won't see
  2692.                the objects, perhaps secret to the quest, go away.
  2693.                Not just 'Print' in case the quest allows the object
  2694.                to be given to someone else. */
  2695.             SPrint(now, FormatName(object@p_oName) + " vanishes.\n");
  2696.         fi;
  2697.         fi;
  2698.     fi;
  2699.     od;
  2700. corp;
  2701.  
  2702. /*
  2703.  * RemoveAllFromInventory - remove all occurrences of the given object
  2704.  *    from the given characters inventory, including inside containers.
  2705.  */
  2706.  
  2707. define tp_util proc scanList(thing who;list thing lt;thing what;bool top)void:
  2708.     int count, i;
  2709.     thing th;
  2710.  
  2711.     count := Count(lt);
  2712.     i := 0;
  2713.     while i ~= count do
  2714.     th := lt[i];
  2715.     if Parent(th) = what then
  2716.         if top then
  2717.         SPrint(who, FormatName(what@p_oName) + " vanishes.\n");
  2718.         fi;
  2719.         ClearThing(th);
  2720.         DelElement(lt, th);
  2721.         count := count - 1;
  2722.     else
  2723.         if th@p_oContents ~= nil then
  2724.         scanList(who, th@p_oContents, what, false);
  2725.         fi;
  2726.         i := i + 1;
  2727.     fi;
  2728.     od;
  2729. corp;
  2730.     
  2731. define t_util proc RemoveAllFromInventory(thing who, what)void:
  2732.  
  2733.     scanList(who, who@p_pCarrying, what, true);
  2734. corp;
  2735.  
  2736. /* create the arrivals room */
  2737.  
  2738. public r_arrivals CreateThing(r_indoors).
  2739. SetupRoom(r_arrivals, "in the arrivals room",
  2740.     "This room is where new players enter the game.").
  2741.  
  2742. /* set up 'SysAdmin' */
  2743.  
  2744. CharacterThing(SysAdmin)@p_pDesc :=
  2745.     "SysAdmin is the mighty creator of the entire known universe. "
  2746.     "His least whim is law. "
  2747.     "Nothing is beyond his power. "
  2748.     "Beware lest you antagonize him!".
  2749. CharacterThing(SysAdmin)@p_pMoney := 10000.
  2750. CharacterThing(SysAdmin)@p_pPrivileged := true.
  2751. /* do this right away so we can add checkers as they are defined */
  2752. CharacterThing(SysAdmin)@p_pEnterActions := CreateActionList().
  2753.  
  2754. /*
  2755.  * newPlayer - this is the routine which we set up to be called when a
  2756.  *    new player is created.
  2757.  */
  2758.  
  2759. define tp_util proc newPlayer()void:
  2760.     string thePlayer;
  2761.     thing me;
  2762.  
  2763.     me := Me();
  2764.     thePlayer := me@p_pName;
  2765.     me@p_pCarrying := CreateThingList();
  2766.     me@p_pHiddenList := CreateThingList();
  2767.     if me@p_pDesc = "" then
  2768.     /* not SysAdmin */
  2769.     me@p_pDesc := thePlayer + " is a nondescript adventurer.";
  2770.     fi;
  2771.     if me@p_pEnterActions = nil then
  2772.     me@p_pEnterActions := CreateActionList();
  2773.     fi;
  2774.     me@p_pMoney := 75;
  2775.     me@p_pVerbose := true;
  2776.     me@p_pSuperBrief := false;
  2777.     me@p_pEchoPose := false;
  2778.     me@p_pStandard := true;
  2779.     me@p_pPosition := POS_NONE;
  2780.     me@p_pWhere := me;
  2781.     me@p_pCursor := MakeCursor();
  2782.     me@p_pCursorColour := C_RED;
  2783.     me@p_pIconColour := C_WHITE;
  2784.     me@p_pTextColours := CreateIntList();
  2785.     AddTail(me@p_pTextColours, 0x000);
  2786.     AddTail(me@p_pTextColours, 0xb80);
  2787.     AddTail(me@p_pTextColours, 0xa60);
  2788.     AddTail(me@p_pTextColours, 0xda0);
  2789.     me@p_MapGroup := NO_MAP_GROUP;
  2790.     SetLocation(r_arrivals);
  2791.     ignore SetCharacterInputAction(parseInput);
  2792.     ignore SetCharacterRawKeyAction(handleRawKey);
  2793.     ignore SetCharacterButtonAction(StandardButtonHandler);
  2794.     ignore SetCharacterMouseDownAction(StandardMouseDownHandler);
  2795.     ignore SetCharacterIdleAction(idleAction);
  2796.     ignore SetCharacterActiveAction(activeAction);
  2797.     if GOn(nil) then
  2798.     InitStandardGraphics();
  2799.     else
  2800.     me@p_pStandardGraphicsDone := false;
  2801.     fi;
  2802.     DoList(me@p_pEnterActions);
  2803.     note - we assume the arrivals room is not dark;
  2804.     ForEachAgent(r_arrivals, ShowIconOnce);
  2805.     OPrint("New player " + thePlayer + " has appeared.\n");
  2806.     Print("Welcome to the sample MUD world, " + thePlayer +
  2807.     "! Your character has been created, but it is quite minimal - "
  2808.     "you are not carrying anything, and your appearance is dull. "
  2809.     "You will soon be able to remedy these conditions. Some of the "
  2810.     "commands available: quit, north, n, up, enter, northeast, verbose, "
  2811.     "terse, inventory, get, drop, look, examine, etc. Have fun!\n");
  2812.     ignore ShowClients(false);
  2813.     ignore ShowRoomToMe(true);
  2814. corp;
  2815.  
  2816. ignore SetNewCharacterAction(newPlayer).
  2817.  
  2818. unuse tp_util
  2819.